Android中原生WebView与HTML5 里的 JS交互

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/hadues/article/details/100746607

在Android 帝国中,使用WebView 如何和HTML5 里面的JS 进行交互呢?

这篇博文我们一起来学习下两个小技巧

  • 在一个Android 应用程序中,使用Webview 接受处理JS 发来的消息,alert 弹出信息
  • 在一个HTML5 页面点击按钮发送一个消息到Webview 后用Toast控件处理这个消息

1.AndroidManifest.xml 配置如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xingyun.webviewwithjssample">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MyWebViewActivity"></activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Tips:
值得注意的是,我们这里配置了两个Activity.

  • MainActivity
    在这里插入图片描述
  • MyWebViewActivity
    在这里插入图片描述
    然后这个界面上两个按钮都是WebView
  • 第一个按钮点击后发送一个字符串给android,然后用Toast 弹出来这个消息。
  • 第二个按钮点击后使用JS中的alert 弹出一个message.
    其次,还配置了三个权限,分别是网络权限,读取和写入存储卷。
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

然后我们写下这两个页面的布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/clickMeBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me"
        android:background="@color/colorPrimary"
        android:textColor="@color/colorWhite"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_my_web_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyWebViewActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        >
        <WebView
            android:id="@+id/myWebView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >
        </WebView>
    </LinearLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

然后编写MainActivity.java

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import static androidx.core.content.PermissionChecker.PERMISSION_GRANTED;

public class MainActivity extends AppCompatActivity {

    Button button;

    private static final int NOT_NOTICE = 2;//如果勾选了不再询问
    private AlertDialog alertDialog;
    private AlertDialog mDialog;

    String[] permissionArray={Manifest.permission.INTERNET,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.clickMeBtn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myRequetPermission();
            }
        });
    }

    private void myRequetPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, permissionArray, 1);
        }else {
            Toast.makeText(this,"您已经申请了权限!",Toast.LENGTH_SHORT).show();
            startActivity(new Intent(MainActivity.this,MyWebViewActivity.class));
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == 1) {
            for (int i = 0; i < permissions.length; i++) {
                if (grantResults[i] == PERMISSION_GRANTED) {//选择了“始终允许”
                    Toast.makeText(this, "" + "权限" + permissions[i] + "申请成功", Toast.LENGTH_SHORT).show();
                    startActivity(new Intent(MainActivity.this,MyWebViewActivity.class));
                } else {
                    if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])){//用户选择了禁止不再询问

                        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                        builder.setTitle("permission")
                                .setMessage("点击允许才可以使用我们的app哦")
                                .setPositiveButton("去允许", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        if (mDialog != null && mDialog.isShowing()) {
                                            mDialog.dismiss();
                                        }
                                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                        Uri uri = Uri.fromParts("package", getPackageName(), null);//注意就是"package",不用改成自己的包名
                                        intent.setData(uri);
                                        startActivityForResult(intent, NOT_NOTICE);
                                    }
                                });
                        mDialog = builder.create();
                        mDialog.setCanceledOnTouchOutside(false);
                        mDialog.show();
                    }else {//选择禁止
                        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                        builder.setTitle("permission")
                                .setMessage("点击允许才可以使用我们的app哦")
                                .setPositiveButton("去允许", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        if (alertDialog != null && alertDialog.isShowing()) {
                                            alertDialog.dismiss();
                                        }
                                        ActivityCompat.requestPermissions(MainActivity.this, permissionArray, 1);
                                    }
                                });
                        alertDialog = builder.create();
                        alertDialog.setCanceledOnTouchOutside(false);
                        alertDialog.show();
                    }

                }
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==NOT_NOTICE){
            myRequetPermission();//由于不知道是否选择了允许所以需要再次判断
        }
    }
}

代码很简单,主要配置了下动态申请了网络权限,读写权限,以及编写了中间按钮的点击跳转页面事件。

然后就是MyWebViewActivity.java

import android.os.Bundle;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MyWebViewActivity extends AppCompatActivity {

    private WebView myWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_web_view);
        myWebView=findViewById(R.id.myWebView);

        myWebView.getSettings().setAllowFileAccess(true);
        myWebView.getSettings().setAllowContentAccess(true);
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.getSettings().setAllowFileAccessFromFileURLs(true);
        myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        myWebView.getSettings().setSupportZoom(true);
        myWebView.addJavascriptInterface(new JSInterface(),"test");
        myWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Log.d("swallow","onJsAlert:"+message);
                return super.onJsAlert(view, url, message, result);
            }
        });
        myWebView.loadUrl("file:///android_asset/index.html");
    }

    //https://www.jianshu.com/p/345f4d8a5cfa
    class JSInterface extends Object{

        @JavascriptInterface
        public void sendToAndroid(String message){
            Log.i("swallow",message);
            Toast.makeText(MyWebViewActivity.this,message,Toast.LENGTH_LONG).show();
        }
    }
}

代码也很简单,主要有两部分:

扫描二维码关注公众号,回复: 7617870 查看本文章
  • 第一部分:监控HTML5页面弹窗
    在这里插入图片描述

关键点: 如果在webview 中想要监控HTML5中的弹窗事件,那么就重写myWebView.setWebChromeClient
中的onJsAlert 方法。 这样操作能处理HTML5 中出现的各种弹窗信息

  • 第二部分:让HTML5页面JS中传递一个message 给Webview 然后用Toast 弹出来。
    在这里插入图片描述

关键点

  • myWebView.addJavascriptInterface(new JSInterface(),“test”); 相当于在JS中创建了一个test对象。
  • 然后在JS中就可以调用 test.sendToAndroid(“js调用了android中的sendToAndroid方法”);
  • 值得注意的是,必须使用@JavascriptInterface注解绑定了sendToAndroid方法,然后在JS中使用才有效。这是为了解决一个JS
    漏洞。
  • 详情参考 你不知道的 Android WebView 使用漏洞

我们需要一个HTML页面放到assets文件夹
在这里插入图片描述
然后目录结构成这样
在这里插入图片描述
index.html 必须绑定

<html>

<head>
    <meta charset="UTF-8"/>
</head>
<script>
        function callAndroid(){
            test.sendToAndroid("js调用了android中的sendToAndroid方法");
        }
        function callJS(){
             alert("alert message From JS");
        }
    </script>
<body>


<div align="center">
    <p>
        <input type="button" value="HTML上点击按钮显示Android Toast" onclick="callAndroid()"/>
    </p>
    <p>
        <input type="button" value="HTML上点击按钮显示JS弹窗" onclick="callJS()"/>
    </p>
</div>

</body>
</html>

源码下载

源码下载

参考链接

猜你喜欢

转载自blog.csdn.net/hadues/article/details/100746607