网站首页 > 技术文章 正文
众所周知,app的一些功能可能会使用到H5开发,这就难免会遇到java与js的相互调用,像android利用WebViewJavascriptBridge实现js和java的交互,这里主要介绍下JsBridge的原理和使用。
一、什么是JSBridge
JSBridge主要是给JavaScript提供调用Native功能的接口,让混合开发中的前端部分可以方便地使用Native的功能(例如:地址位置、摄像头)。而且JSBridge的功能不止调用Native功能这么简单宽泛。
JSBridge是一座用JavaScript搭建起来的桥,一端是Web,一端是Native,是Native和Web之间的桥梁。我们搭建这座桥的目的也很简单,让Native可以调用Web的js代码,让Web可以“调用”原生的代码。它的核心是构建Native和Web间消息通信的通道,而且这个通信的通道是双向的。
双向通信的通道:
JS向Native发送消息:调用相关功能、通知Native当前JS的相关状态等。
Native向JS发送消息:回溯调用结果、消息推送、通知JS当前Native的状态等。
H5与Native交互如下图:
二、JSBridge的实现原理
JavaScript是运行在一个单独的JS Context中(例如WebView的Webkit引擎、JSCore)。由于这些Context与原生运行环境的天然隔离,我们可以将这种情况与RPC(Remote Procedure Call,远程过程调用)通信进行类比,将Native与JavaScript的每次互相调用看做一次RPC调用。
在JSBridge的设计中,可以把前端看做RPC的客户端,把Native端看做RPC的服务器端,从而JSBridge要实现的主要逻辑就出现了:通信调用(Native与JS通信)和句柄解析调用。
三、JSBridge的通信原理
1.JavaScript调用Native的方式
主要有两种:注入API和拦截URL SCHEME
1.1 注入API
注入API方式的主要原理是,通过WebView提供的接口,向JavaScript的Context(window)中注入对象或者方法,让JavaScript调用时,直接执行相应的Native代码逻辑,达到JavaScript调用Native的目的。
iOS
UIWebVIew(iOS2+)和WKWebView(iOS8+)的调用方式有所区别
//假设ios客户端约定方法名为nativeBridge
//UIWebView
window.nativeBridge(message);
//WKWebView
window.webkit.messageHandlers.nativeBridge.postMessage(message);
Android
原理:通过WebView提供的addJavascriptInterface方法给浏览器window注入一个命名空间,然后给Web增加一些可以操作Java的反射。
//addJavascriptInterface
mWebView.addJavascriptInterface(new Class(), 'android');
//@JavascriptInterface
public class Class(){
@JavascriptInterface
public void method(){
}
}
//js 代码
window.android.method();
备注:在4.2之前,Android注入JavaScript对象的接口是addJavascriptInterface,但是这个接口有漏洞,可以被不法分子利用,危害用户的安全,因此在4.2中引入新的接口@JavascriptInterface(上面代码中使用的)来替代这个接口,解决安全问题。
1.2 拦截URL SCHEME
解释一下URL SCHEME:URL SCHEME是一种类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的url近似,主要区别是protocol和host一般是自定义的。
例如:
esign://home/url?url=www.baidu.com,
protocol是esign,host则是home。
拦截URL SCHEME 的主要流程是:Web端通过某种方式(例如iframe.src)发送URLScheme请求,之后Native拦截到请求并根据URL SCHEME(包括所带的参数)进行相关操作。
在时间过程中,这种方式有一定的缺陷:
- 使用iframe.src发送URLSCHEME会有url长度的隐患。
为什么选择iframe.src不选择locaiton.href?
因为如果通过location.href连续调用Native,很容易丢失一些调用。
因此:JavaScript调用Native推荐使用注入API的方式
2.Native调用JavaScript的方式
相比于JavaScript调用Native,Native调用JavaScript较为简单,直接执行拼接好的JavaScript代码即可。
从外部调用JavaScript中的方法,因此JavaScript的方法必须在全局的window上。
iOS
对于iOS的UIWebView,示例如下:
//UIWebView
result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
对于iOS的WKWebView,示例如下:
//WKWebView
[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
Android
Android
在Kitkat(4.4)之前是使用webview的loadUrl进行调用的:
webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");
而Kitkat之后的版本,也可以用evaluateJavascript方法实现:
webView.evaluateJavascript(javaScriptString,new ValueCallback<String>() {
@Override
publicvoidonReceiveValue(String value){
}
});
四、JSBridge 接口实现
从上面的剖析中,可以得知,JSBridge的接口主要功能有两个:调用Native(给Native发消息)和接被Native调用(接收Native消息)。因此,JSBridge可以设计如下:
window.JSBridge = {
// 调用 Native
invoke: function(msg) {
// 判断环境,获取不同的 nativeBridge
nativeBridge.postMessage(msg);
},
receiveMessage: function(msg) {
// 处理 msg
}
};
在上面部分中,提到过RPC中有一个非常重要的环节是句柄解析调用,这点在JSBridge中体现为句柄与功能对应关系。同时,我们将句柄抽象为桥名(BridgeName),最终演化为一个BridgeName对应一个Native功能或者一类Native消息。基于此点,JSBridge的实现可以优化为如下:
window.JSBridge = {
// 调用 Native
invoke: function(bridgeName, data) {
// 判断环境,获取不同的 nativeBridge
nativeBridge.postMessage({
bridgeName: bridgeName,
data: data || {}
});
},
receiveMessage: function(msg) {
var bridgeName = msg.bridgeName,
data = msg.data || {};
//具体逻辑
}
};
终极提问:消息都是单向的,那么调用Native功能时Callback怎么实现的?
对于JSBridge的Callback,其实就是RPC框架的回调机制。当然也可以用更简单的JSONP机制解释:
当发送JSONP请求时,url参数里会有callback参数,其值是当前页面唯一的,
而同时以此参数值为key将回调函数存到window上,随后,
服务器返回script中,也会以此参数值作为句柄,调用相应的回调函数。
整体流程:
在Native端配合实现JSBridge的JavaScript调用Native逻辑也很简单,主要的代码逻辑是:接收到JavaScript消息=>解析参数,拿到bridgeName、data和callbackId=>根据bridgeName找到功能方法,以data为参数执行=>执行返回值和callbackId一起回传前端。
Native调用JavaScript也同样简单,直接自动生成一个唯一的ResponseId,并存储句柄,然后和data一起发送给前端即可。
五、JSBridge的总结
对于JSBridge的引用,常用有如下两种方式,但各有利弊。
1.由Native端进行注入
注入方式和Native调用JavaScript类似,直接执行桥的全部代码。
它的优点是:
桥的版本很容易与Native保持一致,Native端不用对不同版本的JSBridge进行兼容。
它的缺点是:
注入时机不确定,需要实现注入失败后重试的机制,保证注入的成功率,同时JavaScript端在调用接口时,需要优先判断JSBridge是否已经注入成功。
2.由JavaScript端引用
直接与JavaScript一起执行。
它的优点是:
JavaScript端可以确定JSBridge的存在,直接调用即可。
它的缺点是:
如果桥的实现方式有更改,JSBridge需要兼容多版本的Native Bridge或者Native Bridge兼容多版本的JSBridge。
至此,JSBridge的原理介绍完毕,欢迎大家转发留言进行交流。
猜你喜欢
- 2024-12-26 最新CRMEB商城多商户java版源码v1.6版本+前端uniapp
- 2024-12-26 React NextJS App Router 实时获取API
- 2024-12-26 六、uni-app + vue3 + ts + vite 响应式原理
- 2024-12-26 一个人生活必须要知道的几款App,告别空虚寂寞冷
- 2024-12-26 看看汽车充电app界面的设计,是不是一场创意盛宴
- 2024-12-26 印度欧美APP商城前端源码下载/多店铺PHP商城源码下载
- 2024-12-26 基于vue.js+uniapp后台管理系统uni-uadmin
- 2024-12-26 基于 vue.js 可视化拖拽低代码VisualDrag
- 2024-12-26 想积累实战经验吗?前端教程_ReactNative项目之美食App不容错过
- 2024-12-26 一、Uni-app + Vue3 + TS +Vite 创建项目步骤
你 发表评论:
欢迎- 494℃几个Oracle空值处理函数 oracle处理null值的函数
- 489℃Oracle分析函数之Lag和Lead()使用
- 487℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 475℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 469℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 464℃【数据统计分析】详解Oracle分组函数之CUBE
- 447℃Oracle有哪些常见的函数? oracle中常用的函数
- 442℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
-
- Spring Boot跨域难题终结者:3种方案,从此告别CORS噩梦!
- 京东大佬问我,SpringBoot为什么会出现跨域问题?如何解决?
- 在 Spring Boot3 中轻松解决接口跨域访问问题
- 最常见五种跨域解决方案(常见跨域及其解决方案)
- Java Web开发中优雅应对跨域问题(java跨域问题解决办法)
- Spring Boot解决跨域最全指南:从入门到放弃?不,到根治!
- Spring Boot跨域问题终极解决方案:3种方案彻底告别CORS错误
- Spring Cloud 轻松解决跨域,别再乱用了
- Github 太狠了,居然把 "master" 干掉了
- IntelliJ IDEA 调试 Java 8,实在太香了
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)