Android实现WebView和Js交互

时间:2023-02-10 14:46:35

概述

今天来看看WebView和Js的交互功能如何实现

效果图

Android实现WebView和Js交互


代码

首先我们需要准备一个html文件,放在assets目录中,方便我们从代码中加载,html的代码如下

<html>
    <head>
        <title>WebView和Js交互</title>
        <script type="text/javascript">
            function updateHtml(){
                document.getElementById("content").innerHTML = "android调用了js的update方法";
            }
        </script>
    </head>
    <body>
        <a onClick="window.android.showToast()" href="#">调用android方法</a><br/>
        <span id="content"></span>
    </body>
</html>

updateHtml方法是被Android调用的,用来更新当前页面的内容

a标签里我们指定了一个onClick属性,它的值是window.android.showToast(),其中android是我们定义的一个对象,通过下面的代码指定

webView.addJavascriptInterface(new JavaScriptInterface(),"android");

addJavaScriptInterface这个方法接收两个参数,第一个指定注入到JavaScript中的Java对象,第二个参数是这个参数的名字,通过window.name.methodName,我们就可以在js中调用android的方法了

showToast是我们在Android中定义的一个方法,Js调用


/**
 * webview和js交互
 */
public class WebJsActivity extends AppCompatActivity {
    private static final String TAG = "WebJsActivity";
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_js);
        webView = (WebView) findViewById(R.id.webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("file:///android_asset/demo.html");
        webView.addJavascriptInterface(new JavaScriptInterface(),"android");
     
    public void updateJs(View view) {
//        webView.loadUrl("javascript:updateHtml()");//js方法无返回值
        //有返回值处理
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
            webView.evaluateJavascript("javascript:updateHtml()", new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    System.out.println("==========" + value);
                }
            });
        } else {
            //19之前java调用js方法,js在调用java方法把返回值传过来
        }

    }

    public class JavaScriptInterface{
        @JavascriptInterface
        public void showToast(){
            Toast.makeText(WebJsActivity.this, "被JS调用了", Toast.LENGTH_SHORT).show();
        }
    }
}

这里我们注意到,Android中的方法加入了一个@JavascriptInterface注解,因为js可以通过反射调用我们的android代码,这样是有安全隐患的,谷歌为了安全,从API17开始,只有添加了这个注解的java方法才能够被js调用,那么API17以下我们想要实现交互,又不发生安全漏洞,要怎么做呢?其实js还有另一种方式调用android代码,

我们稍微修改下js的代码

<html>
    <head>
        <title>WebView和Js交互</title>
        <script type="text/javascript">
            function updateHtml(){
                document.getElementById("content").innerHTML = "android调用了js的update方法";
                return "success";
            }
            function callAndroid(){
                document.location = "abc://webview?age=1&name=lxn";
            }
        </script>
    </head>
    <body>
        <a onClick="callAndroid()" href="#">调用android方法</a><br/>
        <span id="content"></span>
    </body>
</html>
这里的主要修改是当我们在js中调用android方法是,不是直接去掉用定义好的某个方法,而是指定的一个协议,进行重定向,然后我们就可以在WebViewClient的shouldOverideUrlLoading方法中进行拦截处理的,代码如下


   //WebChromeClient主要处理js的对话框
        webView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                return super.onJsAlert(view, url, message, result);
            }

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });
        //WebViewClient主要处理各种通知,事件
        webView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                checkUri(Uri.parse(url));
                return true;
            }
        });
    }

    public void checkUri(Uri uri){
        Log.d(TAG, "shouldOverrideUrlLoading: " + uri.getScheme());
        Log.d(TAG, "shouldOverrideUrlLoading: " + uri.getAuthority());//webview
        String age = uri.getQueryParameter("age");//1
        String name = uri.getQueryParameter("name");//lxn
        Log.d(TAG, "shouldOverrideUrlLoading: " + age +"--"+name);
        if (uri.getScheme().equals("abc")) {
            //这里调用android的方法
            Toast.makeText(this, "通过url调用", Toast.LENGTH_SHORT).show();
        }
    }