为什么要用 JSBridge

顾名思义,JSBridge是js和Native之间通信的桥梁

  1. Android4.2以下,addJavascriptInterface方式有安全漏洞。
  2. url scheme交互方式是一套现有的成熟方案,可以完美兼容各种版本,便于拓展,无重大安全性问题

另外,请注意,可以理解为JSBridge是一种交互理念,而上述的url scheme则是其中的一种实现。


实现思路

方案一

由前端页面通过某种方式触发scheme(如用iframe.src),然后Native用某种方法捕获对应的url触发事件,然后拿到当前的触发url,根据定义好的协议,分析当前触发了那种方法,然后根据定义来执行。

方案二

仔细回忆一下,WebView有一个方法,叫setWebChromeClient,可以设置WebChromeClient对象,而这个对象中有三个方法,分别是onJsAlert,onJsConfirm,onJsPrompt,当js调用window对象的对应的方法,即window.alert,window.confirm,window.prompt,WebChromeClient对象中的三个方法对应的就会被触发,我们是不是可以利用这个机制,自己做一些处理呢?答案是肯定的。至于js这三个方法的区别,可以详见w3c JavaScript消息框。一般来说,我们是不会使用onJsAlert的,为什么呢?因为js中alert使用的频率还是非常高的,一旦我们占用了这个通道,alert的正常使用就会受到影响,而confirm和prompt的使用频率相对alert来说,则更低一点。那么到底是选择confirm还是prompt呢,其实confirm的使用频率也是不低的,比如你点一个链接下载一个文件,这时候如果需要弹出一个提示进行确认,点击确认就会下载,点取消便不会下载,类似这种场景还是很多的,因此不能占用confirm。而prompt则不一样,在Android中,几乎不会使用到这个方法,就是用,也会进行自定义,所以我们完全可以使用这个方法。该方法就是弹出一个输入框,然后让你输入,输入完成后返回输入框中的内容。因此,占用prompt是再完美不过了。

到这一步,我们已经找到了JSBridge双向通信的一个通道了,接下来就是如何实现的问题了。


原理概述

JSBridge是Native代码与JS代码的通信桥梁。目前的一种统一方案是:H5触发url scheme->Native捕获url scheme->原生分析,执行->原生调用h5。如下图:

url scheme介绍:

1.url scheme是一种类似于url的链接,是为了方便app直接互相调用设计的

具体为,可以用系统的OpenURI打开一个类似于url的链接(可拼入参数),然后系统会进行判断,如果是系统的url scheme,则打开系统应用, 否则找看是否有app注册这种scheme,打开对应app

需要注意的是,这种scheme必须原生app注册后才会生效,如微信的scheme为(weixin://)

2.而本文JSBridge中的url scheme则是仿照上述的形式的一种方式

具体为,app不会注册对应的scheme,而是由前端页面通过某种方式触发scheme(如用iframe.src),然后Native用某种方法捕获对应的url触发事件,然后拿到当前的触发url,根据定义好的协议,分析当前触发了那种方法,然后根据定义来执行


实现流程

一、关键步骤分析

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

如下图:

二、分步实现

1、第一步:设计出一个Native与JS交互的全局桥对象

我们规定,JS和Native之间的通信必须通过一个H5全局对象JSbridge来实现,该对象有如下特点

  • 该对象名为"JSBridge",是H5页面中全局对象window的一个属性
var JSBridge = window.JSBridge || (window.JSBridge = {});
  • 该对象有如下方法

registerHandler( String,Function ), H5调用  注册本地JS方法,注册后Native可通过JSBridge调用。调用后会将方法注册到本地变量messageHandlers 中

callHandler( String,JSON,Function ),H5调用  调用原生开放的api,调用后实际上还是本地通过url scheme触发。调用时会将回调id存放到本地变量responseCallbacks

_handleMessageFromNative( JSON ), Native调用  原生调用H5页面注册的方法,或者通知H5页面执行回调方法

  • 如图

2、第二步:JS如何调用Native

在第一步中,我们定义好了全局桥对象,可以我们是通过它的callHandler方法来调用原生的,那么它内部经历了一个怎么样的过程呢?如下

callHandler函数内部实现过程

在执行callHandler时,内部经历了以下步骤:

  • (1)判断是否有回调函数,如果有,生成一个回调函数id,并将id和对应回调添加进入回调函数集合responseCallbacks
  • (2)通过特定的参数转换方法,将传入的数据,方法名一起,拼接成一个url scheme
    ​
    //url scheme的格式如
    //基本有用信息就是后面的callbackId,handlerName与data
    //原生捕获到这个scheme后会进行分析
    var uri = CUSTOM_PROTOCOL_SCHEME://API_Name:callbackId/handlerName?data
  • (3)使用内部早就创建好的一个隐藏iframe来触发scheme

    //创建隐藏iframe过程
    var messagingIframe = document.createElement('iframe');
    messagingIframe.style.display = 'none';
    document.documentElement.appendChild(messagingIframe);//触发scheme
    messagingIframe.src = uri;

    注意,正常来说是可以通过window.location.href达到发起网络请求的效果的,但是有一个很严重的问题,就是如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。所以JS端发起网络请求的时候,需要使用iframe,这样就可以避免这个问题。---引自参考来源

3、第三步:Native如何得知api被调用

在上一步中,我们已经成功在H5页面中触发scheme,那么Native如何捕获scheme被触发呢?

在Android中(WebViewClient里)

此处也有两种实现方案,选取其中的一种即可

方案一:通过iframe.src来触发scheme,native端通过重写setWebViewClient的shouldoverrideurlloading可以捕获到url scheme的触发

方案二:通过window.prompt(uri, "")来触发,native端通过重写WebViewClient的onJsPrompt来获取uri

详细细节请往下查看实现示例中“捕获url scheme并执行方法的代码”

4、第四步:分析url-参数和回调的格式

在前面的步骤中,Native已经接收到了JS调用的方法,那么接下来,原生就应该按照定义好的数据格式来解析数据了,url scheme的格式前面已经提到。Native接收到Url后,可以按照这种格式将回调参数id、api名、参数提取出来,然后按如下步骤进行

  • (1)根据api名,在本地找寻对应的api方法,并且记录该方法执行完后的回调函数id
  • (2)根据提取出来的参数,根据定义好的参数进行转化

    如果是JSON格式需要手动转换,如果是String格式直接可以使用

  • (3)原生本地执行对应的api功能方法
  • (4)功能执行完毕后,找到这次api调用对应的回调函数id,然后连同需要传递的参数信息,组装成一个JSON格式的参数

    回调的JSON格式为:{responseId:回调id,responseData:回调数据}  (1)responseId String型 H5页面中对应需要执行的回调  函数的id,在H5中生成url scheme时就已经产生  (2)responseData JSON型 Native需要传递给H5的回调数据,是一个JSON格式:{code:(整型,调用是否成功,1成功,0失败),result:具体需要传递的结果信息,可以为任意类型,msg:一些其它值}

  • (5)通过JSBridge通知H5页面回调

5、第五步:Native如何调用JS

到了这一步,就该Native通过JSBridge调用H5的JS方法或者通知H5进行回调了,具体如下

//将回调信息传给H5
JSBridge._handleMessageFromNative(messageJSON); 

如上,实际上是通过JSBridge的_handleMessageFromNative传递数据给H5,其中的messageJSON数据格式根据两种不同的类型,有所区别,如下

Native被动通知H5页面进行回调

数据格式为:{responseId:回调id,responseData:回调数据}

Native主动调用H5方法

数据格式是:{handlerName:api名,data:数据,callbackId:回调id}

  • handlerName String型 需要调用的,h5中开放的api的名称
  • data JSON型 需要传递的数据,固定为JSON格式(因为我们固定H5中注册的方法接收的第一个参数必须是JSON,第二个是回调函数)
  • callbackId String型 原生生成的回调函数id,h5执行完毕后通过url scheme通知原生api成功执行,并传递参数

注意,这一步中,如果Native调用的api是h5没有注册的,h5页面上会有对应的错误提示。

另外,H5调用Native时,Native处理完毕后一定要及时通知H5进行回调,要不然这个回调函数不会自动销毁,多了后会引发内存泄漏。

6、第六步:H5中api方法的注册以及格式

前面有提到Native主动调用H5中注册的api方法,那么h5中怎么注册供原生调用的api方法呢?格式又是什么呢?如下

H5中注册供原生调用的API

//注册一个测试函数
JSBridge.registerHandler('testH5Func',function(data,callback){alert('测试函数接收到数据:'+JSON.stringify(data));callback&&callback('{"result":"回调成功"}');
});

如上述代码为注册一个供原生调用的api

H5中注册的API格式注意

如上代码,注册的api参数是(data,callback)

其中第一个data即原生传过来的数据,第二个callback是内部封装过一次的,执行callback后会触发url scheme,通知原生获取回调信息


实现示例

一、JS实现部分

核心类JSBridge.js

(function() {(function() {var hasOwnProperty = Object.prototype.hasOwnProperty;var JSBridge = window.JSBridge || (window.JSBridge = {});//jsbridge协议定义的名称var CUSTOM_PROTOCOL_SCHEME = 'tolvgx';//最外层的api名称var API_Name = 'tolvgx_bridge';//进行url scheme传值的iframevar messagingIframe = document.createElement('iframe');messagingIframe.style.display = 'none';messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;document.documentElement.appendChild(messagingIframe);//定义的回调函数集合,在原生调用完对应的方法后,会执行对应的回调函数idvar responseCallbacks = {};//唯一id,用来确保每一个回调函数的唯一性var uniqueId = 1;//本地注册的方法集合,原生只能调用本地注册的方法,否则会提示错误var messageHandlers = {};//当原生调用H5注册的方法时,通过回调来调用(也就是变为了异步执行,加强安全性)var dispatchMessagesWithTimeoutSafety = true;//本地运行中的方法队列var sendMessageQueue = [];//实际暴露给原生调用的对象var Inner = {/*** @description 注册本地JS方法通过JSBridge给原生调用* 我们规定,原生必须通过JSBridge来调用H5的方法* 注意,这里一般对本地函数有一些要求,要求第一个参数是data,第二个参数是callback* @param {String} handlerName 方法名* @param {Function} handler 对应的方法*/registerHandler: function(handlerName, handler) {messageHandlers[handlerName] = handler;},/*** @description 调用原生开放的方法* @param {String} handlerName 方法名* @param {JSON} data 参数* @param {Function} callback 回调函数*/callHandler: function(handlerName, data, callback) {//如果没有 dataif(arguments.length == 3 && typeof data == 'function') {callback = data;data = null;}_doSend({handlerName: handlerName,data: data}, callback);},/*** iOS专用* @description 当本地调用了callHandler之后,实际是调用了通用的scheme,通知原生* 然后原生通过调用这个方法来获知当前正在调用的方法队列*/_fetchQueue: function() {var messageQueueString = JSON.stringify(sendMessageQueue);sendMessageQueue = [];return messageQueueString;},/*** @description 原生调用H5页面注册的方法,或者调用回调方法* @param {String} messageJSON 对应的方法的详情,需要手动转为json*/_handleMessageFromNative: function(messageJSON) {setTimeout(_doDispatchMessageFromNative);/*** @description 处理原生过来的方法*/function _doDispatchMessageFromNative() {var message;try {message = JSON.parse(messageJSON);} catch(e) {//TODO handle the exceptionconsole.error("原生调用H5方法出错,传入参数错误");return;}//回调函数var responseCallback;if(message.responseId) {//这里规定,原生执行方法完毕后准备通知h5执行回调时,回调函数id是responseIdresponseCallback = responseCallbacks[message.responseId];if(!responseCallback) {return;}//执行本地的回调函数responseCallback(message.responseData);delete responseCallbacks[message.responseId];} else {//否则,代表原生主动执行h5本地的函数if(message.callbackId) {//先判断是否需要本地H5执行回调函数//如果需要本地函数执行回调通知原生,那么在本地注册回调函数,然后再调用原生//回调数据有h5函数执行完毕后传入var callbackResponseId = message.callbackId;responseCallback = function(responseData) {//默认是调用EJS api上面的函数//然后接下来原生知道scheme被调用后主动获取这个信息//所以原生这时候应该会进行判断,判断对于函数是否成功执行,并接收数据//这时候通讯完毕(由于h5不会对回调添加回调,所以接下来没有通信了)_doSend({handlerName: message.handlerName,responseId: callbackResponseId,responseData: responseData});};}//从本地注册的函数中获取var handler = messageHandlers[message.handlerName];if(!handler) {//本地没有注册这个函数} else {//执行本地函数,按照要求传入数据和回调handler(message.data, responseCallback);}}}}};/*** @description JS调用原生方法前,会先send到这里进行处理* @param {JSON} message 调用的方法详情,包括方法名,参数* @param {Function} responseCallback 调用完方法后的回调*/function _doSend(message, responseCallback) {if(responseCallback) {//取到一个唯一的callbackidvar callbackId = Util.getCallbackId();//回调函数添加到集合中responseCallbacks[callbackId] = responseCallback;//方法的详情添加回调函数的关键标识message['callbackId'] = callbackId;}var uri;//android中,可以通过onJsPrompt或者截取Url访问都行var ua = navigator.userAgent;if(ua.match(/(iPhone\sOS)\s([\d_]+)/)||ua.match(/(iPad).*OS\s([\d_]+)/)) {//ios中,通过截取客户端url访问//因为ios可以不暴露scheme,而是由原生手动获取//正在调用的方法详情添加进入消息队列中,原生会主动获取sendMessageQueue.push(message);uri = Util.getUri();}else{//android中兼容处理,将所有的参数一起拼接到url中uri = Util.getUri(message);}//获取 触发方法的url scheme//采用iframe跳转scheme的方法messagingIframe.src = uri;}var Util = {getCallbackId: function() {//如果无法解析端口,可以换为Math.floor(Math.random() * (1 << 30));// return 'cb_' + (uniqueId++) + '_' + new Date().getTime();return Math.floor(Math.random() * (1 << 30));},//获取url scheme//第二个参数是兼容android中的做法//android中由于原生不能获取JS函数的返回值,所以得通过协议传输getUri: function(message) {var uri = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;if(message) {//回调id作为端口存在var callbackId, method, params;if(message.callbackId) {//第一种:h5主动调用原生callbackId = message.callbackId;method = message.handlerName;params = message.data;} else if(message.responseId) {//第二种:原生调用h5后,h5回调//这种情况下需要原生自行分析传过去的port是否是它定义的回调callbackId = message.responseId;method = message.handlerName;params = message.responseData;}//参数转为字符串params = this.getParam(params);//uri 补充uri += ':' + callbackId + '/' + method + '?' + params;}return uri;},getParam: function(obj) {if(obj && typeof obj === 'object') {return JSON.stringify(obj);} else {return obj || '';}}};for(var key in Inner) {if(!hasOwnProperty.call(JSBridge, key)) {JSBridge[key] = Inner[key];}}})();//注册一个测试函数JSBridge.registerHandler('testH5Func', function(data, callback) {alert('测试函数接收到数据:' + JSON.stringify(data));callback && callback('测试回传数据...');});
})();           

测试界面index.html

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>JSBridge</title><meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=0"><script type="text/javascript" src="JSBridge.js"></script></head><body><button type="button" onclick="click1()">H5调用原生方法</button><br/><br/><button type="button" onclick="click2()">H5调用原生方法并回调</button></body><script>function click1(){JSBridge.callHandler('testFormH5',{type:'fromH5'},function(res){})}function click2(){JSBridge.callHandler('testFormH5AndBack',{type:'fromH5AndBack'},function(res){alert(res.formNative);})}</script>
</html>

二、Android实现部分

1. JSBridge类实现,这个类的作用是原生定义一些暴露的api。

public class JSBridge {private static Map<String, HashMap<String, Method>> exposedMethods = new HashMap<>();public static void register(String exposedName, Class<BridgeImpl> clazz) {if (!exposedMethods.containsKey(exposedName)) {try {exposedMethods.put(exposedName, getAllMethod(clazz));} catch (Exception e) {e.printStackTrace();}}}private static HashMap<String, Method> getAllMethod(Class injectedCls) throws Exception {HashMap<String, Method> mMethodsMap = new HashMap<>();Method[] methods = injectedCls.getDeclaredMethods();for (Method method : methods) {String name;if (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (name = method.getName()) == null) {continue;}Class[] parameters = method.getParameterTypes();if (null != parameters && parameters.length == 3) {if (parameters[0] == WebView.class && parameters[1] == JSONObject.class && parameters[2] == Callback.class) {mMethodsMap.put(name, method);}}}return mMethodsMap;}public static String callJava(WebView webView, String uriString) {String methodName = "";String className = "";String param = "{}";String port = "";if (!TextUtils.isEmpty(uriString) && uriString.startsWith("tolvgx")) {Uri uri = Uri.parse(uriString);className = uri.getHost();param = uri.getQuery();port = uri.getPort() + "";String path = uri.getPath();if (!TextUtils.isEmpty(path)) {methodName = path.replace("/", "");}}Log.i("js_bridge_uri:---", uriString+"");if (exposedMethods.containsKey(className)) {HashMap<String, Method> methodHashMap = exposedMethods.get(className);if (methodHashMap != null && methodHashMap.size() != 0 && methodHashMap.containsKey(methodName)) {Method method = methodHashMap.get(methodName);if (method != null) {try {method.invoke(null, webView, new JSONObject(param), new Callback(webView, port));} catch (Exception e) {e.printStackTrace();}}}}return null;}
}

注意:其中39行的"tolvgx"需要与JS端的CUSTOM_PROTOCOL_SCHEME一致!

2. Callback类实现,这个类的作用是定义原生中的回调函数。

public class Callback {private static Handler mHandler = new Handler(Looper.getMainLooper());private static final String CALLBACK_JS_FORMAT = "javascript:JSBridge._handleMessageFromNative('%s');";private String mPort;private WeakReference<WebView> mWebViewRef;//Java被调用使用public Callback(WebView view, String port) {mWebViewRef = new WeakReference<>(view);mPort = port;}//Java主动调用js使用public Callback(WebView view) {mWebViewRef = new WeakReference<>(view);}public void apply(JSONObject jsonObject) {final String execJs = String.format(CALLBACK_JS_FORMAT, String.valueOf(jsonObject));if (mWebViewRef != null && mWebViewRef.get() != null) {mHandler.post(new Runnable() {@Overridepublic void run() {mWebViewRef.get().loadUrl(execJs);}});}}public String getPort(){return mPort;}
}

注意:其中第3行的_handleMessageFromNative('%s')对应JS端的_handleMessageFromNative(messageJSON)方法

3. Webview容器关键代码实现

注册api方法

//定义api集合
JSBridge.register("tolvgx_bridge",BridgeImpl.class);    

注意:此处的"tolvgx_bridge"需要和JS端的API_Name一致。

捕获url scheme并执行方法的代码

和JS对应,此处也有两种实现方案,选取其中的一种即可

方案一:如果JS端通过iframe.src来触发scheme,则

public boolean shouldOverrideUrlLoading(WebView view, String url){if(url.contains("tolvgx://")){//读取到url后通过callJava分析调用JSBridge.callJava(view, url);} else {// 当有新连接时,使用当前的 WebViewview.loadUrl(url);}//如果返回false,则WebView处理链接url,如果返回true,代表WebView根据程序来执行urlreturn true;
}

注意:第二行的"tolvgx://"需要和JSBridge中39行的"tolvgx"匹配。

方案二:如果JS端通过window.prompt(uri, "")来触发,则

setWebChromeClient(new WebChromeClient() {@Overridepublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {result.confirm(JSBridge.callJava(view, message));return true;}
}

4. API 类实现

这个类是一些api的具体实现,webview里面就是注册了这些对应的api

JS调用Native

如果js主动调用app, (1)需要回调,则app需返回responseId (2)无需回调, 则app可不返回responseId

/*** 针对数据的详细解析:*           JSONObject object = new JSONObject();*           JSONObject data = new JSONObject();*           object.put("responseId", callback.getPort());*           object.put("callbackId", "xxx");*           object.put("handlerName", "xxx");*           object.put("responseData", data);**     1.如果js主动调用app, 1.需要回调,则app需返回responseId 2.无需回调, 则app可不返回responseId*     2.如果app主动调用js, 不要返回responseId, **.需要回调, 则app需js返回callbackId*                                           **.无需回调, 则js可不返回callbackId*                                           **.handlerName是app主动调用js方法时和js约定好的方法*                                           **.其中callbackId为客户端随机生成*/public class BridgeImpl  {/*h5调用原生方法,不回调*/public static void testFormH5(WebView webView, JSONObject param, final Callback callback) {String type = param.optString("type");BrowserActivity activity = (BrowserActivity) webView.getContext();Log.d("testFormH5", "type: "+type);switch (type) {case "fromH5":Toast.makeText(activity, type, Toast.LENGTH_LONG).show();break;}}/*h5调用原生方法,并回调*/public static void testFormH5AndBack(WebView webView, JSONObject param, final Callback callback) {String type = param.optString("type");BrowserActivity activity = (BrowserActivity) webView.getContext();Log.d("testFormH5AndBack", "type: "+type);try {JSONObject data = new JSONObject();switch (type) {case "fromH5AndBack":Toast.makeText(activity, type, Toast.LENGTH_LONG).show();data.put("formNative", "回调成功");break;}if (null != callback) {JSONObject object = new JSONObject();object.put("responseId", callback.getPort());object.put("responseData", data);callback.apply(object);}} catch (Exception e){e.printStackTrace();}}/*原生调用h5后回调的原生方法*/public static void testH5Func(WebView webView, JSONObject param, final Callback callback) {String result = param.optString("result");BrowserActivity activity = (BrowserActivity) webView.getContext();Log.d("testH5Func", result+"");Toast.makeText(activity, result+"", Toast.LENGTH_LONG).show();}
}

Native调用JS

如果app主动调用js,不要返回responseId,**.需要回调,则app需要js返回callbackId
                                                                      **.无需回调,则js可不返回callbackId
                                                                      **.handlerName是app主动调用js方法时和js约定好的方法
                                                                      **.其中callbackId为客户端随机生成

(1)无需回调,如下:

JSONObject data = new JSONObject();
try {data.put("fromNative", "不回调");Callback callback = new Callback(mWebView);JSONObject object = new JSONObject();object.put("handlerName", "testH5Func");object.put("data", data);callback.apply(object);
} catch (JSONException e) {e.printStackTrace();
}

(2)需要回调,如下:

JSONObject data = new JSONObject();
try {data.put("fromNative", "回调");Callback callback = new Callback(mWebView);JSONObject object = new JSONObject();object.put("handlerName", "testH5Func");object.put("data", data);object.put("callbackId", getCallbackId());callback.apply(object);
} catch (JSONException e) {e.printStackTrace();
}

注意:回调方法和调用的h5方法名称一致,在BridgeImpl类中实现。


至此,我们已经把JSBridge的原理和实现示例全部讲完,希望对您有所帮助,谢谢。

按照惯例,上源码。

https://github.com/tolvgx/JSBridge

JSBridge的原理与实现相关推荐

  1. jsbridge实现及原理_Android JSBridge的原理与实现

    原标题:Android JSBridge的原理与实现 JSBridge 在Android中,JSBridge已经不是什么新鲜的事物了,各家的实现方式也略有差异.大多数人都知道WebView存在一个漏洞 ...

  2. JSBridge 技术原理分析

    -     JSBridge的起源    - PhoneGap(Codova 的前身)作为 Hybrid 鼻祖框架,是一个开源的移动开发框架,允许你用标准的web技术-HTML5,CSS3和JavaS ...

  3. JSBridge的原理及使用

    一.什么是JSBridge 主要是给 JavaScript 提供调用 Native 功能的接口,让混合开发中的前端部分可以方便地使用 Native 的功能(例如:地址位置.摄像头). 而且 JSBri ...

  4. JSBridge通信原理

    JSBridge是个啥 直接来重点,记住:JSBridge 是一个很简单的东西,更多的是一种形式.一种思想,为了解决 H5 和 Native 的双向通信. 就像我们刚接触 ajax 时,也很懵逼.其实 ...

  5. android 混编JsBridge的原理和实现

    首先我们先要知道 js调用Android的方法有以下四种: WebView的JavascriptInterface WebViewClient.shouldOverrideUrlLoading() W ...

  6. jsbridge实现及原理_JSBridge 实现原理解析

    JSBridge 项目以 js 与 android 通信为例,讲解 JSBridge 实现原理,下面提到的方法在 iOS(UIWebview 或 WKWebview)均有对应方法. 1. native ...

  7. 深入浅出JSBridge:从原理到使用

    一.前言 在如今移动端盛行的年代,技术选型上基本都是混合开发(Hybrid),混合开发是一种开发模式,指使用多种开发模型开发App,通常会涉及到两大类技术:原生Native.Web H5 原生技术主要 ...

  8. jsbridge实现及原理_jsBridge原理解析

    导语 现在大多数App与H5的交互越来越多,jsBridge是一个能使webView和js交互的通信方式,本文只对https://github.com/lzyzsd/JsBridge(以下涉及到的js ...

  9. jsbridge实现及原理_JsBridge使用和原理

    What is JsBridge 近期在做一个项目,使用的是Native+H5的方式实现的.众所周知的是在Android中,Webview所实现的java与js的交互存在一些安全问题,并且这样的使用方 ...

最新文章

  1. [置顶] 正则表达式应用:匹配IP地址
  2. 【计算理论】可判定性 ( 丘奇-图灵论题 | 可判定性引入 | 图灵机语言 | 图灵机结果 | 判定机 | 部分函数与全部函数 | 可判定性定义 )
  3. Linux 服务器安装discuz 7.2论坛
  4. 动态规划生产存储matlab,基于Matlab的动态规划算法的实现及应用
  5. 学习C++/C的宏与for循环的结合
  6. 求数组三项之和最接近某个目标数字
  7. UI设计素材|社交界面模板
  8. mysql ignore space_MySQL日志存储空间满引发的错误
  9. log4j的org.apache.log4j.PatternLayout
  10. 微博同步ValidatorException
  11. javascript基础之拖拽(2)(详细篇)---FileReader对象,blod对象
  12. 【软件工程】对软件工程课程的希望及个人目标
  13. Windows(多)操作系统启动过程
  14. 暑假将至,人贩子猖狂
  15. OpenNLP 自然语言处理工具
  16. HP惠普游戏笔记本Win10打游戏死机蓝屏无法正常开机【记录】
  17. Elasticsearch - Fuzzy query
  18. Android——一个简单的记账本APP
  19. 微信小程序开发—背景图片全屏(无白条)
  20. USB ncm虚拟网卡

热门文章

  1. 【C++】构造函数与析构函数
  2. 贵州省计算机专业有哪些二本大学,贵州二本大学有哪些?见贵州二本排名
  3. 阿里在线编程测试题–派送货物,求最短路径(C语言实现)
  4. “看不见的眼睛”——电脑监控软件能做什么?
  5. 翻译计算机缩略词GDDR,计算机缩略语精选
  6. Android入门第20天-Android里的ScrollView的使用
  7. 微信指纹支付设置出现java6_怎么设置微信指纹支付-有微信钱包的一定要设置,这六把安全锁保护你的钱财安全...
  8. Android手机蓝牙连接热敏打印机 打印票据
  9. 第二十五天到第二十七天 倒数开始 滴答滴 滴答滴-IFE
  10. P4197 Peaks