Android与前端交互之JSBridge

    在app中,经常会遇到一些活动推广的页面,大多数活动具备时效性强、运营时间短的特征,这些活动一般都是通过H5页面快速投放到产品的活动模块,来和用户进行交互。如何建立web页面和本地Native页面的深度交互,这就接下来要重点介绍的JSBridge,先看一个效果图:图一JS调用Android,图二Android调用JS。






Android调用JS

    在android为我们提供了WebView,他有三个方法loadUrl,LoadData,LoadDataWithBase
    (1)loadUrl:这个url可以是一个远程的网络路径,也可以是一个本地的uri地址。
    (2)LoadData:是LoadUri的增强版,可以指定编码格式,不至于造成乱码
    (3)LoadDataWithBase:可以指定资源路径,例如一个网页可能包含image,css,js文件夹,这时候如果使用loadUrl会导致图片资源无法加载,布局错乱,这时候需要使用这个方法指定资源路径。

    通过以上三种方式android就可以和web进行通信了,同时android也为我们提供了addJavascriptInterface,该方法负责把Object 对象暴露成 JavaScript中的name对象。WebView存在一个漏洞,该漏洞已经在Android 4.2上修复了,即使用@JavascriptInterface代替addJavascriptInterface。另外一个问题是在Android4.4版本之前WebView使用的是Webkit,在之后的版本中采用Chromium浏览器内核标准,由于以上安全性和兼容性问题,基本上不会使用系统原生的一些方法,这里可以使用JSBridge来进行web端和android端的数据通讯。

JS调用Android

(1)webView.addJavascriptInterface()
(2)WebViewClient.shouldOverrideUrlLoading()
(3)WebChromeClient.onJsAlert()/onJsConfirm()/onJsPrompt() 方法分别回调拦截JS对话框alert()、confirm()、prompt()消息。

JSBridge与Android通信原理

    JSBridge是一座用JavaScript搭建起来的桥,替代了WebView的自带的JavascriptInterface的接口,使得我们的开发更加灵活和安全。一端是web,一端是native,他可以根据web和native约定好的规则来通知native要做什么,从而实现Android和Javascript之间的交互。
    
    在Android调用JS我们可以使用WebView.loadUrl(“javascript:function()”)进行加载,但是当H5调用Android时却不是那么方便了。先来看看JSBridge与Android之间的通信原理:
    
    在WebView中,有一个setWebChromeClient方法,可设置WebChromeClient对象,而这个对象中有三个方法,分别是onJsAlert,onJsConfirm,onJsPrompt,当js调用window对象的对应的方法,即window.alert,window.confirm,window.prompt,WebChromeClient对象中的三个方法对应的就会被触发,这时候WebView的shouldOverrideUrlLoading根据传输协议就会拦截到消息,就可以在这些方法里面进行Android中方法的调用。基于此原理,JSBridge制定了一个通信协议,类似于http协议中url传输协议,来看看统一资源标识符URI组:http://host:port/path?param=value,在JSBridge中的也是类似于这种协议,如下:

    jsbridge://className:port/methodName?jsonObj

(1)className:Android端实现暴露给前端的类名;

(2)port:Android返回结果给前端的端口;

(3)methodName:前端需要调用的函数 ;

    网页端给Android传递的参数,这里传递的是一个json对象,当H5页面调用进行操作时,通过JSBridge出发一个uri  scheme,通过scheme传递一些参数数据,Android捕获到这些消息后会根据scheme中的信息调用相应的方法,执行完毕后调用JSBridge对象回调方法,并且传入结果和id,最后H5再回调此结果,得到反馈。如下图: 


可以总结为以下三点:

1、Android调用通过loadUrl(url)调用JS对象,可以在URL内传递参数。
2、JS调用Android是通过shouldOverrideUrlLoading拦截uri。
3、JsBridge将数据封装成Message,然后放进Queue,再将Queue通过协议进行传输。

Android端使用

1.引入库文件

在repositories 下引入:maven { url "https://jitpack.io" }

在dependencies引入: compile 'com.github.lzyzsd:jsbridge:1.0.4‘

2.初始化设置

        final BridgeWebView bridgeWebView = (BridgeWebView) findViewById(R.id.JsBridgeWebView);
        bridgeWebView.setDefaultHandler(new DefaultHandler());
        bridgeWebView.setWebChromeClient(new WebChromeClient());
        bridgeWebView.loadUrl("file:///android_asset/a.html");

3.注册回调

        /**
         * js调用Android
         *
         *  参数一:getUserInfo就是注册供JS调用的方法名,
         *  参数二:data是JS传过来的参数,
         *  参数三:CallBackFunction 函数中需要把JS需要的response返回给JS
         */
        bridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                Log.e("TAG", "js返回:" + data);
                //显示js传递给Android的消息
                Toast.makeText(MainActivity.this, "js返回:" + data, Toast.LENGTH_LONG).show();
                //Android返回给JS的消息
                function.onCallBack("我是js调用Android返回数据:" + etText.getText().toString());
            }
        });

 如上图一演示情况,打印日志如下:


        /**
         * Android调用js
         *
         * 参数一:js中的方法名称
         * 参数二:Android传递给js数据
         * 参数三:回调接口,data为Android调用js方法的返回数据
         */
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                bridgeWebView.callHandler("functionInJs", "Android调用js的方法", new CallBackFunction() {
                    @Override
                    public void onCallBack(String data) {
                        Log.e("TAG", "onCallBack:" + data);
                        Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
                    }
                });
            }
        });

 如上图二演示情况,打印日志如下:


注意:以上回调用法的传递名submitFromWeb、functionInJs必须与js保持一致。

网页端使用

以下为web端使用示例,备注标明的很详细:

<html>
<head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    <title>js调用java</title>
</head>
<body>
<p>
    <input type="text" id="text1" value="请输入测试数据" width="400px" height="200px"/>
</p>
<p>
    <input type="button" id="enter" value="调用安卓的方法" οnclick="testClick();"
    />
</p>


<script>

         //js调用Android方法:接收Android传递过来的数据,并做处理

         function testClick() {

          //参数一:调用java中的方法   submitFromWeb是方法名,必须和Android中注册时候的方法名称保持一致
          //参数二:返回给Android端的数据,可以为字符串,json等信息
          //参数三:js接收到Android传递过来的数据之后的相应处理逻辑

            window.WebViewJavascriptBridge.callHandler(
               'submitFromWeb'
               , {'param': "JS成功接收到数据---"}
               , function(responseData) {
                    alert(responseData)
               }
           );
       }

       //JS注册事件监听
       function connectWebViewJavascriptBridge(callback) {
           if (window.WebViewJavascriptBridge) {
               callback(WebViewJavascriptBridge)
           } else {
               document.addEventListener(
                   'WebViewJavascriptBridgeReady'
                   , function() {
                       callback(WebViewJavascriptBridge)
                   },
                   false
               );
           }
       }

        //注册回调函数,第一次连接时调用 初始化函数
       connectWebViewJavascriptBridge(function(bridge) {
            //初始化
           bridge.init(function(message, responseCallback) {
               var data = {
                   'Javascript Responds': 'Wee!'
               };
               responseCallback(data);
           });


           //Android调用js方法:functionInJs方法名称需要保持一致 ,并返回给Android通知

           bridge.registerHandler("functionInJs", function(data, responseCallback) {
                alert(data);
               var data = document.getElementById("text1").value;
               var responseData = "我是Android调用js方法返回的数据---"+ data;
               responseCallback(responseData);
           });
       })

</script>

</body>
</html>

 Android端、网页端代码如上,都有详细的备注,理解起来应该不难,最后附上源码,如对你有帮助送上一颗星吧:

https://github.com/yoonerloop/AndroidJSBridge点击打开链接吐舌头吐舌头吐舌头



  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
是的,为了实现在Web页面中与iOS和Android原生应用程序之间的交互,可以使用JSBridgeJSBridge是一个桥接工具,可以将JavaScript与原生应用程序之间的通信连接起来。 在iOS中,可以使用JavaScriptCore框架和WKWebView来实现JSBridge。在Android中,可以使用WebView和JavaScriptInterface来实现JSBridge。 具体来说,需要在原生应用程序中创建一个JavaScriptInterface类,该类可以实现JavaScript与原生代码之间的通信。然后在Web页面中,可以通过JavaScript调用原生应用程序中的方法。 例如,在iOS中,可以使用以下代码创建一个JavaScriptInterface类: ``` @objc class JSInterface: NSObject { weak var webView: WKWebView? init(webView: WKWebView) { self.webView = webView super.init() } @objc func showToast(_ message: String) { let alertController = UIAlertController(title: "Toast", message: message, preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) alertController.addAction(okAction) self.webView?.viewController?.present(alertController, animated: true, completion: nil) } } ``` 然后在Web页面中,可以通过以下代码调用原生应用程序中的showToast方法: ``` window.webkit.messageHandlers.jsInterface.postMessage({action: 'showToast', message: 'Hello world!'}); ``` 在Android中,可以使用以下代码创建一个JavaScriptInterface类: ``` public class JSInterface { private Context context; public JSInterface(Context context) { this.context = context; } @JavascriptInterface public void showToast(String message) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } } ``` 然后在Web页面中,可以通过以下代码调用原生应用程序中的showToast方法: ``` window.jsInterface.showToast('Hello world!'); ``` 通过这种方式,可以实现JavaScript与iOS和Android原生应用程序之间的交互
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值