参考 Android WebView与JS的交互方式:https://blog.csdn.net/u011035026/article/details/123267616
代码示例:
package com.jay.wvjsapp;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Set;

public class MainActivity extends Activity {
    private WebView mWv1;
    Context ctx = this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWv1 = findViewById(R.id.wv1);

        WebSettings webSettings = mWv1.getSettings();
        // 允许javascript 设置支持JS就自动打开IndexedDB存储机制
        webSettings.setJavaScriptEnabled(true);
        // 设置允许JS弹窗
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

        webSettings.setPluginState(WebSettings.PluginState.ON);
        webSettings.setDomStorageEnabled(true);
        webSettings.setAppCacheEnabled(true);
        mWv1.setHorizontalScrollBarEnabled(true);
        mWv1.setVerticalScrollBarEnabled(true);

        //设置响应js 的Alert()函数
        mWv1.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                Log.d("MainActivity","newProgress:"+ newProgress );
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
                Log.d("MainActivity","标题:"+ title);
            }

            //设置响应js 的Alert()函数
            @Override
            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder b = new AlertDialog.Builder(ctx);
                b.setTitle("");
                b.setMessage(message);
                b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                });
                //设置为false,按返回键不能退出。默认为true。
                //弹出框如果要求用户必须点击按钮才关闭(点击页面空白或者点击返回键都不能关闭),那么需设置cancelable为false,
                //如果需要返回键执行事件,那么需要编写对应的监听方法setOnKeyListener
                b.setCancelable(false);
                b.create().show();
                return true;
            }

            //设置响应js 的Confirm()函数
            @Override
            public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder b = new AlertDialog.Builder(ctx);
                b.setTitle("");
                b.setMessage(message);
                b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                });
                b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.cancel();
                    }
                });
                b.create().show();
                return true;
            }

            // js调用Android方法,方式3。
            // 设置拦截js的Prompt()函数,调用Android方法。
            // 在js中调用prompt(),result就是Android返回的值。
            // var result = prompt("js://webview?arg1=111&arg2=222");
            // 拦截输入框(原理同方式shouldOverrideUrlLoading)
            // 参数message:代表prompt()的内容(不是url)
            // 参数result:代表输入框的返回值
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
                Log.d("MainActivity","Prompt input is :" + message);

                // 根据协议的参数,判断是否是所需要的url(原理同方式2)
                // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                //传入进来的 url="js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)
                Uri uri = Uri.parse(message);
                // 如果url的协议 = 预先约定的 js 协议,就解析往下解析参数
                if (uri.getScheme().equals("js")) {
                    // 如果 authority = 预先约定协议里的webview,即代表符合约定的协议
                    // 所以拦截url,下面JS开始调用Android需要的方法
                    if (uri.getAuthority().equals("webview")) {
                        // 执行JS所需要调用的逻辑
                        System.out.println("js调用了Android的方法");
                        // 可以在协议上带有参数并传递到Android上
                        HashMap<String, String> params = new HashMap<>();
                        // 携带的参数名集合
                        Set<String> collection = uri.getQueryParameterNames();
                        for (String item : collection) {
                            // 根据参数名,获取uri中的参数值。
                            params.put(item, uri.getQueryParameter(item));
                        }
                        //参数result:代表消息框的返回值(输入值),返回给客户端js。
                        result.confirm("Android回调给JS的数据为useid=123456");
                    }
                    return true;
                } else {
                    result.confirm();
                }
                return super.onJsPrompt(view, url, message, message, result);
            }

        });

        // js调用Android方法,方式1
        // 通过addJavascriptInterface()将Java对象映射到JS对象
        // 参数1:JavaScript对象名,参数2:Java对象名
        // WebViewJsBridge类对象映射到JS的Android对象
//        mWv1.addJavascriptInterface(new WebViewJsBridge(), "Android");

        String urlAddress = "http://192.168.9.8:5196/Home/Index";
        mWv1.loadUrl(urlAddress);

        // js调用Android方法,方式2
        // 先载入JS代码,格式规定为:file:///android_asset/文件名.html
        // mWv1.loadUrl("file:///android_asset/Test.html");
        // 先载入JS代码,然后复写WebViewClient类的shouldOverrideUrlLoading方法
        mWv1.setWebViewClient(new WebViewClient() {
            // 该重载方法不建议使用了,7.0系统以上已经摒弃了
            // shouldOverrideUrlLoading(WebView view, String url)此方法,
            // 如果要拦截URL,需要做兼容性处理,重写
            // shouldOverrideUrlLoading(WebView view, WebResourceRequest request)方法,
            // 获取得到的可正常使用的URL
//            @Override
//            public boolean shouldOverrideUrlLoading(WebView view, String url) {
//                return super.shouldOverrideUrlLoading(view, url);
//            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                // 根据协议的参数,判断是否是所需要的url
                // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                // 假定传入进来的url="js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)
                Uri uri;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    uri = request.getUrl();
                } else {
                    uri = Uri.parse(request.toString());
                }
                // 如果url的协议 = 预先约定的 js 协议,就解析往下解析参数
                if (uri.getScheme().equals("js")) {
                    // 如果 authority = 预先约定协议里的webview,即代表都符合约定的协议
                    // 所以拦截url,下面JS开始调用Android需要的方法
                    if (uri.getAuthority().equals("webview")) {
                        //执行JS所需要调用的逻辑
                        Log.d("TAG", "JS调用了Android的方法");
                        // 可以在协议上带有参数并传递到Android上
                        HashMap<String, String> params = new HashMap<>();
                        Set<String> collection = uri.getQueryParameterNames();
                        for (String item : collection) {
                            params.put(item, uri.getQueryParameter(item));
                        }
                        String result = "{\"msg\":\"返回数据:123456\"}";
//                        view.loadUrl("javascript:returnResult('" + result + "')");
                        callClientJs("returnResult",result);
                    }
                    return true;
                }
                return super.shouldOverrideUrlLoading(view, request);
            }
        });

    }

    /**
     * 调用客户端js
     * callClientJs("callJs","{\"name\":\"jay.x\"}");
     * */
    public void callClientJs(String methodName, String para) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //方式2:通过WebView的evaluateJavascript()
            //优点:该方法比第一种方法效率更高、使用更简洁。
            //(1)因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。
            //(2)Android 4.4(即>=19)后才可使用。
            // 只需要将第一种方法的loadUrl()换成下面该方法即可
            mWv1.evaluateJavascript("javascript:" + methodName + "('" + para + "')", new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    // 此处为JS返回的结果
                    Toast.makeText(getApplicationContext(), "js return:" + value, Toast.LENGTH_SHORT).show();
                }
            });
        } else {
            //方式1:通过WebView的loadUrl
            mWv1.loadUrl("javascript:" + methodName + "('" + para + "')");
        }
    }

}

 //WebSettings.LOAD_NO_CACHE 设置去缓存,防止加载的为上一次加载过的LOAD_DEFAULT
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

posted on 2023-07-11 09:57  邢帅杰  阅读(65)  评论(0编辑  收藏  举报