android与js的交互

android与js的交互在android开发中是很常见,一般是利用webView当作桥梁,进而实现android调用js,js调用android代码。下面就这两种待用具体记录一下。

android调用js代码

方式1,利用loadUrl

众所周知,webview加载网页时,使用是loadUrl()方法,例如我们加载本地的网页代码可以实现如下:

mWebView = findViewById(R.id.webview);mWebView.loadUrl("file:///android_asset/html/Share.html");

当然,也可以用loadUrl加载非本地的网页,我们甚至还可以用loadUrl来运行js代码。
例如Share.html中的js代码如下:

  function test() {        console.log("[share_debug] test");    }

那么,我们在加载完Share.html之后,我们就可以利用loadUrl来执行test方法了。代码如下:

mWebView.setWebViewClient(new WebViewClient(){            @Override            public void onPageFinished(WebView webView, String s) {                super.onPageFinished(webView, s);               mWebView.loadUrl("javascript:test()");            }        });

这一段核心就只有一句loadUrl,调用他之后就会直接调用android代码。值得注意的时,用loadUrl只有在页面加载完了之后才能运行js代码,也就时在onPageFinished回调之后,否则不会调用到js代码,并且调用loadUrl会使得页面刷新。

方式2,利用evaluateJavascript

在android4.4之后,我们就可以通过evaluateJavascript来执行js代码了。还是以方式1中js中的test方法为例,androi端的调用就可以这么实现:

    mWebView.evaluateJavascript("javascript:test()", new ValueCallback() {        @Override        public void onReceiveValue(String value) {            //此处为 js 返回的结果        }    });}

evaluateJavascript()方法执行之后,并不会使得页面刷新,所以他的执行效率比loadUrl要高,并且我们可以很方便的得到js执行的返回值,但是注意要兼容4.4以下的版本。

总结

使用建议:在能使用evaluateJavascript尽量使用evaluateJavascript,并使用loadUrl保证兼容性.

 if(Build.VERSION.SDK_INT < 18) {            mWebView.loadUrl("javascript:test()");        } else {            mWebView.evaluateJavascript("javascript:test()", null);        }

js调用android代码

js调用android代码方法大致有三种,下面分别进行介绍。

使用addJavascriptInterface注释

这种方式就相当于将android方法映射给js,使得js可以直接调用android代码
示例代码如下:

在Android中需要给方法添加addJavascriptInterface注释来进行映射。
参考代码如下:

    mWebView = findViewById(R.id.webView);    WebSettings settings = mWebView.getSettings();    settings.setJavaScriptEnabled(true); // 设置允许js交互    mWebView.addJavascriptInterface(new IJavaScriptInterface(), "api"); // 将对象映射到js方法中去    mWebView.loadUrl("file:///android_asset/test.html");private class IJavaScriptInterface {    // 注意这个注释    @JavascriptInterface    public void testCalledByJs(String msg) {        Log.d(TAG, "testCalledByJs: "+msg);    }}

对应的js调用就比较简单了,就是映射过来的对象+. + 映射的方法。上栗中我们的对象是api,方法是testCalledByJs,所有调用就应该是api.testCalledByJs("test1");
参考如下:

function testCallAndroid1(){            console.log("test1");            api.testCalledByJs("test1");}

注意,这种方法在4.2版本以下时有严重的漏洞,在4.2以下的版本不应该使用这种方式。

URL拦截

这种方式就是通过在android端拦截js的url跳转,如果判断时指定的url就执行对应的android代码指令。
在androi端,通过WebViewClientshouldOverrideUrlLoading获取到js的跳转指令,通过解析url,判断是我们需要解析的指令,就指定对应的方法,并返回true。
例如我们在android端可以这么写:

    mWebView = findViewById(R.id.webView);    WebSettings settings = mWebView.getSettings();    settings.setJavaScriptEnabled(true); // 设置允许js交互    mWebView.loadUrl("file:///android_asset/test.html");    mWebView.setWebViewClient(new WebViewClient(){            @Override            public boolean shouldOverrideUrlLoading(WebView webView, String s) {                if(s.equals("control:cancel")) {                    onCancel();// 对应的android方法。这里就不进行实现了                    return true;                }                return super.shouldOverrideUrlLoading(webView, s);            }        });

在js里面的调用也特别简单,代码如下:

    function testCancel() {        document.location = "control:cancel";    }

当然,我们完全可以在url里传一些指定的参数,来进行参数传递,我们只需要在shouldOverrideUrlLoading中解析中来即可。

方法拦截

与URL方法来接类似,我们可以通过拦截js中的一些方法来实现js调用android的方法。
我们常用的拦截js的方法主要包括: alert()(弹出警告框,没有返回值),confirm()(弹出确认框,有两个返回值),prompt()(弹出输入框,任意设置返回值)。我们在android端通过实现WebChromeClient中的onJsAlert()onJsConfirm()onJsPrompt()来拦截上述的三个方法。
常见的拦截都是拦截prompt方法,因为只有prompt可以返回任意类型的数据,操作更加全面、也更加灵活。
下面就以拦截js的prompt方法为例,实现js调用android端的方法。
在android端实现如下:

我们把拦截的方法单独成类,譬如我们可以这么写:

class hijackWebChromeClient extends WebChromeClient {    String TAG = "tag";    @Override    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {        // 根据协议的参数,判断是否是所需要的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("demo")) {                // 执行JS所需要调用的逻辑                Log.d(TAG,"js调用了Android的方法");                // 可以在协议上带有参数并传递到Android上                HashMap params = new HashMap<>();                Set collection = uri.getQueryParameterNames();                //参数result:代表消息框的返回值(输入值)                result.confirm("js调用了Android的方法成功啦");            }            return true;        }        return super.onJsPrompt(view, url, message, defaultValue, result);    }    // 拦截JS的警告框    @Override    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {        return super.onJsAlert(view, url, message, result);    }    // 拦截JS的确认框    @Override    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {        return super.onJsConfirm(view, url, message, result);    }}

在拦截js的方法的实现类中,我们仅实现了一个onJsPrompt,用于实现拦截js的prompt方法,其他的可以自行实现。实现了对方法的拦截,我们将其设置给目标webView即可。

    WebSettings settings = mWebView.getSettings();    settings.setJavaScriptEnabled(true); // 设置允许js交互    settings.setJavaScriptCanOpenWindowsAutomatically(true); //允许js弹窗    mWebView.loadUrl("file:///android_asset/test.html");    mWebView.setWebChromeClient(new hijackWebChromeClient());

在js中的调用相对来说就简单了,参考下面的调用就好了。

function testCallAndroid3(){        console.log("test3");        // 调用prompt()        var result = prompt("js://demo?arg1=111&arg2=222");        console.log("get data " + result);    }

总结

js调用android方法一共有三种,第一种是直接映射给js进行调用,使用简单,但是在4.2以下的版本中存在重大安全漏洞,第二中是通过android端拦截js的URL来进行实现,但是如果js不好获取其返回值,第三种是通过android端拦截js的方法来进行实现,这种方法比较灵活,基本能满足开发需求,但是需要相关协议进行约束,否者不好管理。

参考链接

  • https://75team.com/post/android-webview-and-js.html
  • https://blog.csdn.net/carson_ho/article/details/64904691

更多相关文章

  1. WebView---Android与js交互实例
  2. Android的NDK开发
  3. 前端h5与 Android/iOS 交互传参
  4. 源码茶舍之android:externalService是什么属性?实现原理?
  5. Android的消息处理机制(深入源码)
  6. Android学习路线
  7. Android(安卓)多线程AsyncTask详解
  8. android的测试工具CTS
  9. Android深入理解WebView——上

随机推荐

  1. 收集android上开源的酷炫的交互动画和视
  2. wheelView自定义android日期时间选择器
  3. Android检查网络是否连接
  4. android实现异步下载过程
  5. The Saygus VPhone V1 clears FCC, Will
  6. butterknife报错 cannot find method "va
  7. (Android) Eclipse "launching delegate"
  8. android数据库操作(二)
  9. Android的Layout及其Param
  10. 监测Android Market是否被下过