android使用JSBridge机制原理

一、什么是JSBridge?
JSBridge(JavaScriptBridge)顾名思义就是用JavaScript搭建的桥梁,那连接的是哪两端呢?–一端是web,一端是native。我们搭建这座桥的目的也很简单,让native可以调用web的js代码,让web可以 “调用” 原生的代码。请注意这个我加了 引号的调用,它并不是直接调用,而是可以根据web和native约定好的规则来通知native要做什么,native可以更具这个来执行相应的代码。
JSBridge另一个叫法及大家熟知的Hybrid app技术。

流程:H5->通过某种方式触发一个url->Native捕获到url,进行分析->原生做处理->Native调用H5的JSBridge对象传递回调。

二、JSBridge比传统的WebView/View/UIWeb相比有什么不同?
有以下考虑才使用JSBridge:

  • Android4.2以下,addJavascriptInterface方式有安全漏掉。
  • iOS7以下,JS无法调用Native。
  • url scheme交互方式是一套现有的成熟方案,可以完美兼容各种版本,对以前老版本技术的兼容。

三、什么是URL scheme?
url scheme是一种类似于url的链接,是为了方便app直接互相调用设计的。具体来讲如果是系统的url scheme,则打开系统应用,否则找看是否有app注册这种scheme,打开对应app。
注:这种scheme必须原生app注册后才会生效。

而在我们实际的开发中,app不会注册对应的scheme,而是由前端页面通过某种方式触发scheme(如用iframe.src),然后Native用某种方法捕获对应的url触发事件,然后拿到当前的触发url,根据定义好的协议,分析当前触发了那种方法。

四、JSBridge技术实现
要实现JSBridge,我们需要按以下步骤分析:

  • 第一步:设计出一个Native与JS交互的全局桥对象。
  • 第二步:JS如何调用Native。
  • 第三步:Native如何得知api被调用。
  • 第四步:分析url-参数和回调的格式。
  • 第五步:Native如何调用JS。
  • 第六步:H5中api方法的注册以及格式

JSBridge的完整流程可总结为:

五、android集成JSBridge

5.1 接入有两种方式:

方式1:直接导入JSBridge的library包即可, AndroidStudio导library包请看博客:AndroidStudio怎样导入library项目开源库
方式2:引入库,在bulid.gradle中添加如下代码
在bulid.gradle(Project.XXX)中allprojects添加

repositories {    maven { url "https://jitpack.io" }}

同时在bulid.gradle(Module.app)中添加

dependencies {    compile 'com.github.lzyzsd:jsbridge:1.0.4'}

5.2 使用方式
5.2.1 默认发送方式
java:

 mBridgeWebView.send("发送数据给web默认接收",new CallBackFunction(){                    @Override                    public void onCallBack(String data) {                        Log.e(TAG, "来自web的回传数据:" + data);                    }                });

js:

bridge.init(function(message, responseCallback) {               bridgeLog('默认接收收到来自Java数据: ' + message);               var responseData = '默认接收收到来自Java的数据,回传数据给你';               responseCallback(responseData);           });

5.2.2 默认接收方式
java:

 mBridgeWebView.setDefaultHandler(new BridgeHandler() {            @Override            public void handler(String data, CallBackFunction function) {                Log.e(TAG,"DefaultHandler接收全部来自web的数据:"+data);                function.onCallBack("DefaultHandler收到Web发来的数据,回传数据给你");            }        });

js:

//第一个参数要发送的数据 第二个参数js在被回调后具体执行方法,responseData为java层回传数据           window.WebViewJavascriptBridge.send(               data               , function(responseData) {                  bridgeLog('来自Java的回传数据: ' +responseData);               }           );

5.3指定自定义参数通信
Html点击事件利用JS function方法调Android端并相互传值:
js:

function testClick1() {           //调用本地java方法           //第一个参数是 调用java的函数名字 第二个参数是要传递的数据 第三个参数js在被回调后具体执行方法,responseData为java层回传数据           var data='发送消息给java代码指定接收';           window.WebViewJavascriptBridge.callHandler(               'submitFromWeb'               ,data               , function(responseData) {                   bridgeLog('来自Java的回传数据: ' + responseData);               }           );       }

java:

//必须和js同名函数,注册具体执行函数,类似java实现类。        //第一参数是订阅的java本地函数名字 第二个参数是回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)        mBridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() {            @Override            public void handler(String data, CallBackFunction function) {                Log.e(TAG, "指定Handler接收来自web的数据:" + data);                function.onCallBack("指定Handler收到Web发来的数据,回传数据给你");            }        });

Android点击事件调用JS方法并相互传值:
java:

findViewById(R.id.to_web).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mBridgeWebView.callHandler("functionInJs","发送数据给web指定接收",new CallBackFunction(){                    @Override                    public void onCallBack(String data) {                        Log.e(TAG, "来自web的回传数据:" + data);                    }                });            }        });

js:

//注册回调函数,第一次连接时调用 初始化函数       connectWebViewJavascriptBridge(function(bridge) {           bridge.registerHandler("functionInJs", function(data, responseCallback) {               bridgeLog('指定接收收到来自Java数据: ' + data);               var responseData = '指定接收收到来自Java的数据,回传数据给你';               responseCallback(responseData);           });       })

完整代码如下:
android View xml界面

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.github.lzyzsd.jsbridge.BridgeWebView        android:id="@+id/test_bridge_webView"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"/>    <Button        android:id="@+id/to_web_default"        android:layout_margin="10dp"        android:layout_width="match_parent"        android:text="默认传递数据给Web"        android:layout_height="wrap_content"/>    <Button        android:id="@+id/to_web"        android:layout_margin="10dp"        android:layout_width="match_parent"        android:text="指定传递数据给Web"        android:layout_height="wrap_content"/>LinearLayout>

android java

package com.example.XXX.myapplication.activity.sysActivity;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.example.XXX.myapplication.R;import com.github.lzyzsd.jsbridge.BridgeHandler;import com.github.lzyzsd.jsbridge.BridgeWebView;import com.github.lzyzsd.jsbridge.CallBackFunction;public class XXXActivity extends Activity {    private static  final  String TAG=XXXActivity.class.getSimpleName();    private BridgeWebView mBridgeWebView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_nine);        initViews();    }    private void initViews(){        mBridgeWebView= (BridgeWebView) findViewById( R.id.test_bridge_webView);        mBridgeWebView.loadUrl("file:///android_asset/wx.html");        mBridgeWebView.setDefaultHandler(new BridgeHandler() {            @Override            public void handler(String data, CallBackFunction function) {                Log.e(TAG,"DefaultHandler接收全部来自web的数据:"+data);                function.onCallBack("DefaultHandler收到Web发来的数据,回传数据给你");            }        });        //必须和js同名函数,注册具体执行函数,类似java实现类。        //第一参数是订阅的java本地函数名字 第二个参数是回调Handler , 参数返回js请求的resqustData,function.onCallBack()回调到js,调用function(responseData)        mBridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() {            @Override            public void handler(String data, CallBackFunction function) {                Log.e(TAG, "指定Handler接收来自web的数据:" + data);                function.onCallBack("指定Handler收到Web发来的数据,回传数据给你");            }        });        findViewById(R.id.to_web_default).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mBridgeWebView.send("发送数据给web默认接收",new CallBackFunction(){                    @Override                    public void onCallBack(String data) {                        Log.e(TAG, "来自web的回传数据:" + data);                    }                });            }        });        findViewById(R.id.to_web).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mBridgeWebView.callHandler("functionInJs","发送数据给web指定接收",new CallBackFunction(){                    @Override                    public void onCallBack(String data) {                        Log.e(TAG, "来自web的回传数据:" + data);                    }                });            }        });    }}

在app文件下创建assets文件夹用于存放本地H5html文件
wx.html

<html><head>    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">    <script >       function testClick() {           //发送消息给java代码           var data = '发送消息给java代码全局接收';           //第一个参数要发送的数据 第二个参数js在被回调后具体执行方法,responseData为java层回传数据           window.WebViewJavascriptBridge.send(               data               , function(responseData) {                  bridgeLog('来自Java的回传数据: ' +responseData);               }           );       }       function testClick1() {           //调用本地java方法           //第一个参数是 调用java的函数名字 第二个参数是要传递的数据 第三个参数js在被回调后具体执行方法,responseData为java层回传数据           var data='发送消息给java代码指定接收';           window.WebViewJavascriptBridge.callHandler(               'submitFromWeb'               ,data               , function(responseData) {                   bridgeLog('来自Java的回传数据: ' + responseData);               }           );       }       function bridgeLog(logContent) {           document.getElementById("log_msg").innerHTML = logContent;       }       //注册事件监听       function connectWebViewJavascriptBridge(callback) {           if (window.WebViewJavascriptBridge) {               callback(WebViewJavascriptBridge)           } else {               document.addEventListener(                   'WebViewJavascriptBridgeReady'                   , function() {                       callback(WebViewJavascriptBridge)                   },                   false               );           }       }       //注册回调函数,第一次连接时调用 初始化函数       connectWebViewJavascriptBridge(function(bridge) {           bridge.init(function(message, responseCallback) {               bridgeLog('默认接收收到来自Java数据: ' + message);               var responseData = '默认接收收到来自Java的数据,回传数据给你';               responseCallback(responseData);           });           bridge.registerHandler("functionInJs", function(data, responseCallback) {               bridgeLog('指定接收收到来自Java数据: ' + data);               var responseData = '指定接收收到来自Java的数据,回传数据给你';               responseCallback(responseData);           });       })   script>head><body><p>WebViewJsBridgep><div>    <button onClick="testClick()">发送数据给默认Handler接收button>div><div>    <button onClick="testClick1()">发送数据给指定Handler接收button>div><div id="log_msg">调用打印信息div>body>html>

更多相关文章

  1. C语言函数的递归(上)
  2. android中数据库创建操作的模式
  3. Android与单片机的信息传输方案
  4. Android(安卓)Architecture Components 之 LiveData
  5. 在Android(安卓)中使用KSOAP2调用WebService
  6. Android(安卓)相机Camera API 使用
  7. Android与MVC设计模式
  8. android的动画相关参数说明
  9. 通过Html网页调用本地安卓(android)app程序代码

随机推荐

  1. Android中的Selector
  2. 如何从UA分辨出Android设备类型
  3. Android(安卓)6.0耳机hook按键接听和挂断
  4. Android一次申请多个动态权限
  5. Android(安卓)核心分析 之七------Servic
  6. 基本空间划分
  7. Android之从网络中获取数据并返回客户端
  8. This text field does not specify an in
  9. unity工程接入Android(安卓)sdk后真机测
  10. android中用XMPP Asmack获取用户朋友的pr