目录

  • 《App与Js交互(一)iOS》
  • 《App与Js交互(二)Android》
  • 《App与Js交互(三)Android、iOS通用解决方案推荐》

示例代码

Demo: https://github.com/gwpp/jsinterface

前言

在《App与Js交互(一)iOS》中我们详细的列举了iOS与JS的各种交互方式,那么Android端的交互又是怎样的呢?下面就来为大家一一介绍。
ps:本人iOS出身,Android学习时间不长,如果有BUG还请在下方评论中及时反馈,感谢非常。

Android系统中的交互

方案一,拦截跳转

  • 初始化:

    // WebView默认是不支持Android&JS通信的,要在WebView初始化的时候打开这个开关mWebView.getSettings().setJavaScriptEnabled(true);
  • 原生调用JS:
    Android调用JS的常规方法有两种,如下:

    • 方法 A:

      mWebView.loadUrl("javascript:alert('1234')");

      是的,你没有看错,就是渲染URL的方法,它也可以用来执行js代码,但是弊端就是执行完了这段代码后WebView上原有的内容有可能会被覆盖,并且拿不到JS方法的return值,所以一般不会使用这种方式。

    • 方法 B:

      String js = "getCookieWithKey('username')";mWebView.evaluateJavascript(js, new ValueCallback() {  @Override  public void onReceiveValue(String s) {    // 这里可以处理被调用js方法的return    showNativeMessage("调用JS方法后得到的返回值是:" + s);  }});

      这种方法会比方法A好很多,首先不会影响WebView原本渲染的内容,其次它还支持JS方法的返回值,所以在正常开发中更多时候用的是方法B。

  • JS调用原生:
    用过WebView的同学应该都知道有个东西叫做WebViewClient,这个东西就可以实现我们的需求——拦截跳转。

    // JS代码 ===========================// 登录window.location = 'app://login?account=13011112222&password=123456';// 登出window.location = 'app://share?title=分享的标题&desc=分享的描述'// Android代码 =======================private void setupWebView() {    WebViewClient webViewClient = new WebViewClient() {    // 老方法    @Override    public boolean shouldOverrideUrlLoading(WebView view, String url) {        Uri uri = Uri.parse(url);        // 如果拦截单的链接是app协议的就说明是我们需要处理的链接        if (uri.getScheme().contentEquals("app")) {            callNative(uri);            // 返回true就是告诉WebView该链接不需要你处理了,已经被我“消费”了。            return true;        }        return super.shouldOverrideUrlLoading(view, url);    }    // 新方法,API21之后支持    @Override    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {        if (Build.VERSION.SDK_INT < 21) {            return super.shouldOverrideUrlLoading(view, request);        }        Uri uri = request.getUrl();        if (uri.getScheme().contentEquals("app")) {            callNative(uri);            return true;        }        return super.shouldOverrideUrlLoading(view, request);    }  };  mWebView.setWebViewClient(webViewClient);}/** * js 调用原生方法时的特殊跳转链接 * @param uri 特殊的跳转链接 */private void callNative(Uri uri){    String host = uri.getHost();    if (host.contentEquals("login")) {        String account = uri.getQueryParameter("account");        String password = uri.getQueryParameter("password");        showNativeMessage(String.format("执行登录操作,账号为:%s,密码为:%s", account, password));    } else if (host.contentEquals("share")) {        String title = uri.getQueryParameter("title");        String desc = uri.getQueryParameter("desc");        showNativeMessage(String.format("执行分享操作,title为:【%s】,desc为:【%s】", title, desc));    }}

方案二,JavaScriptInterface

  • 初始化:

    // WebView默认是不支持Android&JS通信的,要在WebView初始化的时候打开这个开关mWebView.getSettings().setJavaScriptEnabled(true);
  • 原生调用JS:
    同方案一的原生调用JS

  • JS调用原生:
    我们可以暴露一个Java的Object给WebView供JS调用。什么意思?就是说JS可以调用我们Java对象的某些方法,这里说的某些方法就是@JavascriptInterface注解修饰的方法,示例如下:

    // JS代码 =========================// 登录app.login("13011112222", "123456");// 登出app.logout();// 获取用户信息var info = app.getLoginUser();showResponse(info);// Android代码 =====================private void setupWebView() {    mWebView.addJavascriptInterface(new JsInterfaceLogic(this), "app");}/**  *  暴露出去给JS调用的Java对象  */class JsInterfaceLogic {    private BaseFragment mFragment;    public JsInterfaceLogic(BaseFragment mFragment) {        this.mFragment = mFragment;    }    @JavascriptInterface    public void login(String account, String password) {        mFragment.showNativeMessage(String.format("执行登录操作,账号为:%s,密码为:%s", account, password));    }    @JavascriptInterface    public void logout() {        mFragment.showNativeMessage("执行【登出】操作");    }    @JavascriptInterface    public String getLoginUser() {        return new JSONObject(new HashMap(4) {{            put("user_id", 666);            put("username", "你就说6不6");            put("sex", "未知");            put("isStudent", false);        }}).toString();    }}

方案三,JSBridge

  • 说明:Android原生是不支持这种方式的,我们需要依赖于一个三方库 —— JsBridge,这是一个很有名的库,具体有多牛逼这里也不做过多需求,百度一下你就知道。

  • 初始化代码:

    // JS初始化代码/** * 初始化jsbridge * @param readyCallback 初始化完成后的回调 */ function initJsBridge(readyCallback) {     var u = navigator.userAgent;     var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端     var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端     // 注册jsbridge     function connectWebViewJavascriptBridge(callback) {         if (isAndroid) {             if (window.WebViewJavascriptBridge) {                 callback(WebViewJavascriptBridge)             } else {                 document.addEventListener(                     'WebViewJavascriptBridgeReady'                     , function () {                         callback(WebViewJavascriptBridge)                     },                     false                 );             }             return;         }         if (isiOS) {             if (window.WebViewJavascriptBridge) {                 return callback(WebViewJavascriptBridge);             }             if (window.WVJBCallbacks) {                 return window.WVJBCallbacks.push(callback);             }             window.WVJBCallbacks = [callback];             var WVJBIframe = document.createElement('iframe');             WVJBIframe.style.display = 'none';             WVJBIframe.src = 'https://__bridge_loaded__';             document.documentElement.appendChild(WVJBIframe);             setTimeout(function () {                 document.documentElement.removeChild(WVJBIframe)             }, 0)         }     }     // 调用注册方法     connectWebViewJavascriptBridge(function (bridge) {         if (isAndroid) {             bridge.init(function (message, responseCallback) {                 console.log('JS got a message', message);                 responseCallback(data);             });         }                   // 只有在这里注册过的方法,在原声代码里才能用callHandler的方式调用         bridge.registerHandler('jsbridge_showMessage', function (data, responseCallback) {             showResponse(data);         });         bridge.registerHandler('jsbridge_getJsMessage', function (data, responseCallback) {              showResponse(data);              responseCallback('native 传过来的是:' + data);          });          readyCallback();      });  }// Android初始化代码mWeb.registerHandler("getOS", new BridgeHandler() {    @Override    public void handler(String data, CallBackFunction function) {        HashMap response = new HashMap(){{            put("error", 0);            put("message", "");            put("data", new HashMap(){{                put("os", "android");            }});        }};        function.onCallBack(response.toString());    }});mWeb.registerHandler("login", new BridgeHandler() {    @Override    public void handler(String data, CallBackFunction function) {        Gson gson = new Gson();        final User user = gson.fromJson(data, User.class);        HashMap response = new HashMap(){{            put("error", 0);            put("message", "");            put("data", String.format("执行登录操作,账号为:%s、密码为:%s", user.getAccount(), user.getPassword()));        }};        function.onCallBack(response.toString());    }});
  • 原生调JS

    // 使用callHandler的方式调用JS中已经注册过的方法mWeb.callHandler("jsbridge_getJsMessage", message, new CallBackFunction() {    @Override    public void onCallBack(String data) {        showNativeMessage(String.format("原生调用JsBridge方法后,Js方法的返回值为:【%s】", data));    }});
  • JS调用原生

    // 首先调用JSBridge初始化代码,完成后再设置其他initJsBridge(function () {  $("#getOS").click(function () {        // 通过JsBridge调用原生方法,写法固定,第一个参数时方法名,第二个参数时传入参数,第三个参数时响应回调        window.WebViewJavascriptBridge.callHandler('getOS', null, function (response) {        showResponse(response);      });  }); });

更多相关文章

  1. Android(安卓)从硬件到应用:一步一步向上爬 4 -- 使用 JNI 方法调
  2. [置顶] Android启动过程——init,Zygote,SystemServer
  3. Android(安卓)之 AsyncTask 异步任务
  4. Android的View和ViewGroup分析
  5. android activity开发文档翻译 - 1 - 基础篇
  6. Android应用AsyncTask处理机制详解及源码分析
  7. Android(安卓)微信分享操作后 在当前界面提示方案 解决
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)root权限判断
  2. android mapview
  3. android 弹出带按钮的对话框
  4. Android(安卓)的AsyncTask使用
  5. Android相机开发那些坑
  6. Android(安卓)jetpack Room数据库(一)基本
  7. 一个android访问http资源的便捷工具类―
  8. Android(安卓)JNI入门第一篇――HelloWor
  9. Android(安卓)访问网络连接设置界面
  10. android 使内容铺满全屏