第二次碰触到混和合作开发如果是在一年前,彼时在做 ionic 和 Cordova(PhoneGap)工程项目的这时候,那些架构在 web 基础上包了几层 Native,接着透过 Bridge 控制技术使 js 可以初始化音频、边线、音音频等机能。现阶段手里负责管理的工程项目则是两个与他家 APP 可视化的混和合作开发工程项目,只好在课余就查了查有关的同时实现计划和基本原理。责任编辑是如是说这层 Bridge 的可视化基本原理,主要就叙述了 js 与 ios 及 android 下层的通讯基本原理及 JSBridge 的PCB控制技术及增容方式。
主要就商业用途
JSBridge 单纯来说,主要是给 JavaScript 提供更多初始化 Native 机能的USB,让混和开发中的后端部份能方便快捷地采用功能定位、探头、控制系统快照等 Native 机能。
但 JSBridge 的商业用途的确不只初始化 Native 机能那么单纯。事实上,JSBridge 就像其中文名称中的 Bridge 的象征意义那样,是 Native 和非 Native 间的公路桥,它的核心理念是构筑 Native 和非 Native 间最新消息通讯的地下通道,所以是点对点的地下通道。
简而言之点对点的地下通道:
JS 向 Native 发送最新消息: 初始化有关机能、通告 Native 现阶段 JS 的有关状况等。Native 向 JS 发送最新消息: 追述初始化结论、最新消息发送、通告 JS 现阶段 Native 的状况等。
同时实现基本原理
主要就分成三个部份,分别是 JavaScript 初始化 Native 和 Native 初始化 JavaScript
JavaScript 初始化 Native
主要就有三种同时实现计划,一类是截击 URL SCHEME ,另一类是转化成API让js间接初始化
截击 URL SCHEME
甚么是 URL SCHEME
由于苹果的 app 都是在沙盒中,相互是不能访问数据的。但苹果还是给出了两个能在 app 间跳转的方式:URL Scheme。URL SCHEME:URL SCHEME 是一类类似于 url 的链接,是为了方便快捷 iosapp 间接互相跳转设计的,形式和普通的 url 近似,主要就区别是 protocol 和 host 一般是自定义的,例如: lefit://leoao/xxxx?xx=123,protocol 是 lefit,host 则是 leoao
同时实现流程在 UIWebView 内发起的所有网络请求,都能透过 delegate 函数在 Native 层得到通告。这样,我们就能在 UIWebView 内发起两个自定义的网络请求,截击 URL SCHEME 的主要就流程是:Web 端透过某种方式(例如 iframe.src)发送 URL Scheme 请求,之后 Native 截击到请求并根据 URL SCHEME(包括所带的参数)进行有关操作。
在实际过程中,这种方式有一定的缺陷:
采用 iframe.src 发送 URL SCHEME 会有 url 长度的隐患。创建请求,需要一定的耗时,比转化成 API 的方式初始化同样的机能,耗时会较长。
但之前为甚么很多计划采用这种方式呢?因为它支持 iOS6。而现在的大环境下,iOS6占比很小,基本上能忽略,所以并不推荐为了 iOS6采用这种并不优雅的方式。
注1:有些计划为了规避 url 长度隐患的缺陷,在 iOS 上采用了采用 Ajax 发送同域请求的方式,并将参数放到 head 或 body 里。这样,虽然规避了 url 长度的隐患,但 WKWebView 并不支持这样的方式。
注2:为甚么选择 iframe.src 不选择 locaiton.href ?因为透过 location.href 有个问题,是如果我们连续多次修改 window.location.href 的值,在 Native 层只能接收到最后一次请求,前面的请求都会被忽略掉。
转化成 API 让 js 间接初始化
转化成 API 方式的主要就基本原理是,透过 WebView 提供更多的USB,向 JavaScript 的 Context(window)中转化成对象或者方式,让 JavaScript 初始化时,间接执行相应的 Native 代码逻辑,达到 JavaScript 初始化 Native 的目的。
iOS
对于 iOS 的 UIWebView,实例如下:
JSContext *context =[uiWebView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”];context[@”postBridgeMessage”]= ^(NSArray
后端初始化方式:
window.postBridgeMessage(message);
对于 iOS 的 WKWebView 能用以下方式:
@interface WKWebVIewVC ()
后端初始化方式:
window.webkit.messageHandlers.nativeBridge.postMessage(message);
Android
对于 Android 可以采用下面的方式:
public class JavaScriptInterfaceDemoActivity extends Activity { private WebView Wv;@Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); Wv =(WebView)findViewById(R.id.webView); final JavaScriptInterface myJavaScriptInterface = new JavaScriptInterface(this); Wv.getSettings().setJavaScriptEnabled(true); Wv.addJavascriptInterface(myJavaScriptInterface,”nativeBridge”);// TODO 显示 WebView } public class JavaScriptInterface { Context mContext; JavaScriptInterface(Context c){ mContext = c;} public void postMessage(String webMessage){// Native 逻辑} }}
后端初始化方式:
window.nativeBridge.postMessage(message);
在4.2之前,Android 转化成 JavaScript 对象的USB是 addJavascriptInterface,但这个USB有漏洞,能被不法分子利用,危害用户的安全,因此在4.2中引入新的USB@JavascriptInterface(上面代码中采用的)来替代这个USB,解决安全问题。所以 Android 转化成对对象的方式是有兼容性问题的。
javascript 执行以下四种行为会被 webview 监听到,箭头后面是对应触发的 Java 方式。由于 prompt 相对来说采用的很少,所以4.2之前很多计划都采用截击 prompt 的方式来同时实现。
1、window.alert => onJSAlert2、window.confirm => onJSConfirm3、window.prompt => onJsPrompt4、window.location => shouldOverrideUrlLoading
Native 初始化 JavaScript
Native 初始化 JavaScript,其实是执行拼接 JavaScript 字符串,从外部初始化 JavaScript 中的方式,因此 JavaScript 的方式必须在全局的 window 上。(闭包里的方式,JavaScript 自己都初始化不了,更不用想让 Native 去初始化了)
iOS
对于 iOS 的 UIWebView,示例如下:
result =[uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
对于 iOS 的 WKWebView,示例如下:
[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
Android
对于 Android,在 Kitkat(4.4)之前并没有提供更多 iOS 类似的初始化方式,只能用 loadUrl 一段 JavaScript 代码,来同时实现:
webView.loadUrl(“javascript:”+ javaScriptString);
而 Kitkat 之后的版本,也能用 evaluateJavascript 方式同时实现:
webView.evaluateJavascript(javaScriptString, new ValueCallback
ipt 执行后的结论。