一、产生背景:
APP面临的挑战:
1.支持复杂业务:App 的业务越来越复杂,不仅仅是内部业务,还包含了大量外部的合作伙伴。如果采用传统的 App 开发方式很难应对日趋复杂的业务场景。
2.满足业务快速迭代的需求:App 开发一个不容忽视的问题,就是应用商店审核。由于审核的存在,App 上开发的业务会有一个统一排期,比如说月底会有新版本,那么所有的业务进度都得考虑 App 的排期计划。
3.性能:如果目前支付宝的业务都是用 Native 开发,大家看到的包大小得增加好几倍,这进一步增加了用户的升级成本。
二、核心:
双向通信的通道
JS 向 Native 发送消息: 调用相关功能、通知 Native 当前 JS 的相关状态等。
Native 向 JS 发送消息: 回溯调用结果、消息推送、通知 JS 当前 Native 的状态等。
三、提供哪些能力
3.1一般JSBridge中实现的通用功能
自定义titleBar
自定义titleBar上左右两侧按钮的功能及样式
打开一个新的webview来承接跳转的url
关闭自身webview
关闭前n个webview
监听resume、pause事件
下拉刷新
app唤起
3.2JSBridge中实现的业务功能
页面分享(微信、微博分享)
登录SDK页面呼启
支付功能
调用相机、图片上传等
定位信息获取
3.3 无法满足
1.不适合传输大量数据(大量数据建议用接口方式获取)
四:历史通信方式
Android端
Native调JS
只要遵循:”javascript: 方法名(‘参数,需要转为字符串’)”的规则即可
在4.4之前,调用的方式:
mWebView = new WebView(this);
mWebView.loadUrl("javascript: 方法名('参数,需要转为字符串')”);
4.4以后(包括4.4),使用以下方式:
mWebView.evaluateJavascript("javascript: 方法名('参数,需要转为字符串')”,
newValueCallback() {}
)
注:4.4之前Native通过loadUrl来调用JS方法,只能让某个JS方法执行,但是无法获取该方法的返回值,(通过js改变iframe.src把结果返回,这样执行效率较低。)4.4之后,通过evaluateJavascript异步调用JS方法,并且能在onReceiveValue中拿到返回值
JS调native
Js调用Native需要对WebView设置@JavascriptInterface注解
Native中通过addJavascriptInterface添加暴露出来的JS桥对象,然后再该对象内部声明对应的API方法。
注:在Android4.2以上(api17后),暴露的api要加上注解@JavascriptInterface,否则会找不到方法。
IOS端
native调js
Native调用js的方法比较简单,Native通过stringByEvaluatingJavaScriptFromString调用Html绑定在window上的函数。
Js调native
Native中通过引入官方提供的JavaScriptCore库(iOS7以上),然后可以将api绑定到JSContext上(然后Html中JS默认通过window.top.*可调用)。
注:iOS7才出现这种方式, 在这之前, js无法直接调用Native, 只能通过JSBridge方式间接调用,iOS原生本身是无法被JS调用的,但是通过引入官方提供的第三方”JavaScriptCore”,即可开放api给JS调用
五、JSbridge
基础:url scheme是一种类似于url的链接,是为了方便app直接互相调用设计的。具体来讲如果是系统的url scheme,则打开系统应用,否则找看是否有app注册这种scheme,打开对应app。
我们常说的 Deeplink 一般也是基于 URL Scheme 来实现的。一个 URI 的组成结构如下:
URI = scheme:[//authority]path[?query][#fragment]
// scheme = http
// authority = www.baidu.com
// path = /link
// query = url=xxxxx
authority = [userinfo@]host[:port]
注:这种scheme必须原生app注册后才会生效。
诞生原因:解决IOS和Android在和JS通信过程中的的低版本兼容问题
流程:H5->通过某种方式触发一个url->Native捕获到url,进行分析->原生做处理->Native调用H5的JSBridge对象传递回调。
方法:
Android 的Webview 提供了 shouldOverrideUrlLoading 方法来提供给 Native 拦截 H5 发送的 URL Scheme
例如:
iOS 的 WKWebview 可以根据拦截到的 URL Scheme 和对应的参数执行相关的操作
六、实现JSBridge步骤分析:
第一步:设计出一个Native与JS交互的全局桥对象
第二步:JS如何调用Native
第三步:Native如何得知api被调用
第四步:分析url-参数和回调的格式
第五步:Native如何调用JS
第六步:H5中api方法的注册以及格式
一、首先有一个全局桥对象
varJSBridge =window.JSBridge || (window.JSBridge = {});
二、Js调用native
通过它的callHandler方法来调用原生的api,
判断是否有回调函数,如果有,生成一个回调函数id,并将id和对应回调添加进入回调函数集合responseCallbacks中。
通过特定的参数转换方法,将传入的数据,方法名一起,拼接成一个url scheme
//基本有用信息就是后面的callbackId,handlerName与data
//原生捕获到这个scheme后会进行分析
varuri = CUSTOM_PROTOCOL_SCHEME://API_Name:callbackId/handlerName?data
注:
正常来说是可以通过window.location.href达到发起网络请求的效果的,但是有一个很严重的问题,就是如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。所以JS端发起网络请求的时候,需要使用iframe,这样就可以避免这个问题。
三、Native如何捕获scheme被触发
Android中(WebViewClient里),通过shouldoverrideurlloading可以捕获到url scheme的触发。
iOS中,UIWebView有个特性:在UIWebView内发起的所有网络请求,都可以通过delegate函数在Native层得到通知
四、URL参数和回调函数格式
1.根据api名,在本地找寻对应的api方法,并且记录该方法执行完后的回调函数id
2.根据提取出来的参数,根据定义好的参数进行转化
3.原生本地执行对应的api功能方法
4.功能执行完毕后,找到这次api调用对应的回调函数id,然后连同需要传递的参数信息,组装成一个JSON格式的参数
5.通过JSBridge通知H5页面回调
五、Native调用JS
到了这一步,就该Native通过JSBridge调用H5的JS方法或者通知H5进行回调了
Native通知H5页面进行回调:
数据格式为: Native通知H5回调的JSON格式。
Native主动调用H5方法:
Native主动调用H5方法时,数据格式是:{handlerName:api名,data:数据,callbackId:回调id}:
1.handlerName String型 需要调用的,h5中开放的api的名称
2.data JSON型 需要传递的数据,固定为JSON格式(因为我们固定H5中注册的方法接收的第一个参数必须是JSON,第二个是回调函数)
3.callbackId String型 原生生成的回调函数id,h5执行完毕后通过url scheme通知原生api成功执行,并传递参数
H5中API方法的注册以及格式
JSBridge.registerHandler('testH5Func',function(data,callback){
alert('测试函数接收到数据:'+JSON.stringify(data));
callback&&callback('测试回传数据…');
}