通过WebChromeClient复写onJsPrompt来调用andriod代码

感觉这个和通过复写shouldOverrideUrlLoading来调用andriod代码有相似之处,但发现了有趣的一点是它在触发后可以把Android的一个数据给返回到JS代码之处;

代码

布局

HTML

在src/main/下创建一个文件夹assets,里面添加一个index.html文件,内容如下;

<html>
<head>
    <meta charset="utf-8">
    <title>emperinter</title>

    <script>

    function clickprompt(){
            var name,password;
            name = document.getElementById("n").value;
            document.getElementById("gn").innerHTML = name;

            password = document.getElementById("p").value;
            document.getElementById("gp").innerHTML = password;

            var data = "js://demo?arg1=" + name + "&arg=" + password + "&arg3=test&fuck=fuck";
            document.getElementById("toandroid").innerHTML = data;

            // 调用prompt(),result为Android传来的值
            var result=prompt(data);
            alert("demo " + result);

            document.getElementById("info").innerHTML = result;
        }

      </script>
</head>


<body>
<div align="center">
    name:<input id="n">
    <br/>
    password:<input id="p">
    <p id="info">Android 传进来的值</p>
    get_name:<p style="color:red;" id="gn">get_name</p>
    get_password:<p style="color:red" id="gp">get_password</p>
    <p id="toandroid">传给Android的一套js数据</p>
    <!-- 点击按钮则调用clickprompt()  -->
    <button style="font-size:32px;" type="button" onclick="clickprompt()">点击调用Android代码</button>
    <p></p>
</div>

</body>
</html>

MainActivity

注意这里的Uri参数是message!

public class MainActivity extends AppCompatActivity {
    WebView mwebview;
    TextView mtxt0;
    TextView mtxt1;

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

        mwebview = (WebView) findViewById(R.id.MainWeb);
        mtxt0 = (TextView) findViewById(R.id.MainTxt0);
        mtxt1 = (TextView) findViewById(R.id.MainTxt1);

        WebSettings websettings = mwebview.getSettings();

        // 允许 WebView 加载 JS 代码
        websettings.setJavaScriptEnabled(true);
        // 允许 JS 弹窗
        websettings.setJavaScriptCanOpenWindowsAutomatically(true);

        try {
            mwebview.loadUrl("file:///android_asset/index.html");
            Log.e("LoadUrl:", "Successful !");
        }catch (Exception ex) {
            Log.e("LoadUrl:", "wrong !");
        }

        mwebview.setWebChromeClient(new WebChromeClient(){
            //拦截输入框(原理同复写shouldOverrideUrlLoading)
            //参数message:代表prompt()的内容(不是url)
            //参数result:代表输入框的返回值
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result){
                //根据协议的参数,判段是否所需要的url
                //一般根据schema(协议格式) & authority(协议名)判断(前两个参数)
                //假定传入进来的 rul = "js://demo?arg1=111&arg2=222" (同时也是约定好需要拦截的)

                Uri uri = Uri.parse(message);
                // 如果url的协议 = 预先约定的js协议
                // 就往下解析参数

                if(uri.getScheme().equals("js")){
                    //如果 authority = 预先约定协议里的webview,即代表都符合约定的协议
                    //所以拦截rul,下面JS开始调用Android需要的方法
                    if(uri.getAuthority().equals("demo")){

                        //参数result:代表消息框的返回值(输入值),这里的参数会传递给JS里面去;
                        result.confirm("从Android向JS返回的数据");

                        Set<String> collection = uri.getQueryParameterNames();
                        Iterator<String> it = collection.iterator();
                        String txt0 = uri.getQueryParameter(it.next());
                        String txt1 = uri.getQueryParameter(it.next());

                        mtxt0.setText(txt0);
                        Log.e("arg1",txt0);
                        mtxt1.setText(txt1);
                        Log.e("arg2",txt1);
////                      测试传参
                        Log.e("test:",uri.getQueryParameter(it.next()));
                        Log.e("fuck:",uri.getQueryParameter(it.next()));


                    }
                    return  true;
                }
                return  super.onJsPrompt(view,url,message,defaultValue,result);
            }

            // 通过alert()和confirm()拦截的原理相同

            // 拦截JS的警告框
//            @Override
//            public boolean onJsAlert(WebView view,String url,String message, JsResult result){
//                return super.onJsAlert(view,url,message,result);
//            }
//
//            // 拦截JS的确认框
//            public boolean onJsConfirm(WebView view,String url,String message,JsResult result){
//                return  super.onJsConfirm(view,url,message,result);
//            }
        });
    }
}

运行截图

除非特别说明,本博客所有作品均采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。转载请注明转自-https://www.emperinter.info/2020/06/06/onjsprompt-on-android-webview/

Leave a Comment