美文网首页
Android通过WebView实现原生Java与JS交互

Android通过WebView实现原生Java与JS交互

作者: lxbnjupt | 来源:发表于2018-06-12 18:22 被阅读0次

    混合开发的App(Hybrid App)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更好又可以节省开发的资源。
    Android提供了一个很强大的WebView控件用来处理Web网页,当然不仅仅就是显示一个WebView那么简单,有时候还需要本地Java代码与HTML中的JS进行交互。所以,在平常的开发中我们总会遇到Android的原生Java代码与网页中的Js代码之间相互调用从而产生的交互问题。

    一、Android原生Java与JS交互方式

    Android原生Java与JS二者之间的沟通的桥梁就是WebView,通过WebView可以实现它们之间的互相调用。
    1.Android原生Java代码调用JS代码
    方式一:通过WebView的loadUrl()方法实现;
    方式二:通过WebView的evaluateJavascript()方法实现;
    2.JS代码调用Android原生Java代码
    方式一:通过WebView的addJavascriptInterface()方法进行对象映射;
    方式二:通过 WebViewClient 的shouldOverrideUrlLoading ()方法进行回调拦截 url;
    方式三:通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息;

    二、Android原生Java代码调用JS代码

    将需要调用的JS代码放到src/main/assets文件夹里(调用本地JS代码和调用远程JS代码均可)
    本地html代码如下:

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type"  content="text/html;charset=UTF-8">
                <script type="text/javascript">
                    function javaCallJsWithNoMessage(){
                        alert("java调用了无参Js");
                    }
    
                    function javaCallJsWithMessage(message){
                        alert(message);
                    }
                </script>
        </head>
    </html>
    

    1.通过WebView的loadUrl()方法实现

    public class JavaCallJsActivity extends AppCompatActivity{
    
        private WebView webView;
        private Button btnCallNoMessage;
        private Button btnCallMessage;
        private Button btnEvaluateJs;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_java_call_js);
    
            btnCallNoMessage = findViewById(R.id.btn_call_with_no_message);// 点击调用无参Js方法
            btnCallMessage = findViewById(R.id.btn_call_with_message);// 点击调用有参Js方法
            btnEvaluateJs = findViewById(R.id.btn_evaluate_js);// 点击通过evaluateJavascript调用Js方法
    
            webView = findViewById(R.id.webview);
            WebSettings webSettings = webView.getSettings();
            webSettings.setJavaScriptEnabled(true);// 设置与Js交互的权限
            webSettings.setJavaScriptCanOpenWindowsAutomatically(true);// 设置允许JS弹窗
            webView.loadUrl("file:///android_asset/hybrid.html");
    
            // 由于设置了弹窗检验调用结果,所以需要支持js对话框,通过设置WebChromeClient对象处理JavaScript的对话框
            webView.setWebChromeClient(new WebChromeClient() {
                @Override
                public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(JavaCallJsActivity.this);
                    builder.setTitle("Alert");
                    builder.setMessage(message);
                    builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            result.confirm();
                        }
                    });
                    builder.setCancelable(false);
                    builder.create().show();
                    return true;
                }
            });
    
            btnCallNoMessage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    javaCallJsWithNoMessage();
                }
            });
    
            btnCallMessage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    javaCallJsWithMessage();
                }
            });
    
            btnEvaluateJs.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //evaluateJavascript();
                }
            });
        }
    
        private void javaCallJsWithNoMessage() {
            webView.post(new Runnable() {
                @Override
                public void run() {
                    webView.loadUrl("javascript:javaCallJsWithNoMessage()");
                }
            });
        }
    
        private void javaCallJsWithMessage() {
            webView.post(new Runnable() {
                @Override
                public void run() {
                    webView.loadUrl("javascript:javaCallJsWithMessage(" + "'Message From Java:略略略'" + ")");
                }
            });
        }
    }
    

    注意:
    (1)WebViewClient类有一个onPageFinished()方法,主要在页面加载结束时调用。JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用。
    (2)调用JS有参方法时,String类型的参数需要使用单引号 “’” 包裹,数组类型的参数则不用,其他复杂类型的参数可以转换为 Json 字符串的形式传递。

    2.通过WebView的evaluateJavascript()方法实现

    private void evaluateJavascript() {
            // 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断
            if (Build.VERSION.SDK_INT < 19) {
                webView.loadUrl("javascript:javaCallJsWithNoMessage()");
            } else {
                webView.evaluateJavascript("javascript:javaCallJsWithNoMessage()", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        //Js返回的结果
                    }
                });
            }
        }
    

    三、JS代码调用Android原生Java代码

    本地html代码如下:

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type"  content="text/html;charset=UTF-8">
                <script type="text/javascript">
                    function jsCallJavaWithMessage(message){
                        jsObj.call(message);
                    }
    
                    function jsCallJavaWithScheme(){
                        /*约定的url协议为:boohee://goods/2018*/
                        document.location = "boohee://goods/2018";
                    }
                </script>
        </head>
        <body>
            <button type="button" onClick="jsCallJavaWithMessage('Message From Js:啦啦啦')" >Js Call Java</button>
            <button type="button" onClick="jsCallJavaWithScheme()" >Js Call Java自定义协议</button>
        </body>
    </html>
    

    1.通过WebView的addJavascriptInterface()方法进行对象映射

    public class JsCallJavaActivity extends AppCompatActivity {
    
        private WebView webView;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_js_call_java);
    
            webView = findViewById(R.id.webview);
            WebSettings webSettings = webView.getSettings();
            webSettings.setJavaScriptEnabled(true);// 设置与Js交互的权限
            webView.addJavascriptInterface(new JSInterface(), "jsObj");//JSInterface类对象映射到js的jsObj对象
            webView.loadUrl("file:///android_asset/hybrid.html");
        }
    
        public class JSInterface {
            // 定义JS需要调用的方法
            // 被JS调用的方法必须加入@JavascriptInterface注解
            @JavascriptInterface
            public void call(String message) {
                Toast.makeText(JsCallJavaActivity.this, message, Toast.LENGTH_LONG).show();
            }
        }
    }
    

    我们可以看到此方式的关键是定义一个与JS对象映射关系的Android类,即JSInterface类。然后,再通过addJavascriptInterface()方法将Java对象映射到JS对象,注意Java代码和JS代码中的jsObj对象名要保持一致。
    注意:JS调用Java方法时,不是在主线程中运行的,而是在一个名为JavaBridge的线程中执行的。所以这里需要注意的是,当JS调用Java时,如果需要Java继续回调JS,千万别在 JavascriptInterface方法体中直接执行 loadUrl() 方法,而是进行线程切换操作。

    2.通过 WebViewClient 的shouldOverrideUrlLoading ()方法进行回调拦截 url

    webView.setWebViewClient(new WebViewClient() {
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    //假设传入的url = "boohee://goods/2018"
                    if (url.contains("boohee://")) {
                        //如何符合约定的协议,则拦截url,开始调用Android的一些方法干事情
                        Toast.makeText(JsCallJavaActivity.this, "Js Call Java自定义协议", Toast.LENGTH_LONG).show();
                        //doSomething
                        return true;
                    }
                    return super.shouldOverrideUrlLoading(view, url);
                }
            });
    

    3.通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息

    本地html代码如下:

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type"  content="text/html;charset=UTF-8">
                <script type="text/javascript">
                    function clickprompt(){
                        // 调用prompt()
                        prompt("boohee://goods/2018");
                    }
                </script>
        </head>
        <body>
            <button type="button" onClick="clickprompt()" >Js Call Java Prompt</button>
        </body>
    </html>
    

    该种方式与方式二的原理类似:
    如果是拦截警告框(即alert()),则触发回调onJsAlert();
    如果是拦截确认框(即confirm()),则触发回调onJsConfirm();
    如果是拦截确认框(即prompt()),则触发回调onJsPrompt();

    webView.setWebChromeClient(new WebChromeClient() {
                @Override
                public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                    //假设传入的url = "boohee://goods/2018"
                    if (message.contains("boohee://")) {
                        //如何符合约定的协议,则拦截url,开始调用Android的一些方法干事情
                        Toast.makeText(JsCallJavaActivity.this, "Js Call Java Prompt", Toast.LENGTH_LONG).show();
                        //doSomething
                        return true;
                    }
                    return super.onJsPrompt(view, url, message, defaultValue, result);
                }
            });
    

    相关文章

      网友评论

          本文标题:Android通过WebView实现原生Java与JS交互

          本文链接:https://www.haomeiwen.com/subject/codreftx.html