简介
主要是给 JavaScript 提供调用 Native 功能的接口,让混合开发中的前端部分可以方便地使用 Native 的功能(例如:地址位置、摄像头)。
实际上,JSBridge 就像其名称中的Bridge的意义一样,是 Native 和非 Native 之间的桥梁,它的核心是构建 Native 和非 Native 间消息通信的通道,而且这个通信的通道是双向的。
双向通信的通道:
JS 向 Native 发送消息: 调用相关功能、通知 Native 当前 JS 的相关状态等。
Native 向 JS 发送消息: 回溯调用结果、消息推送、通知 JS 当前 Native 的状态等。
交互图:
javascript执行以下四种行为会被webview监听到,箭头后面是对应触发的Java方法。
1、window.alert => onJSAlert
2、window.confirm => onJSConfirm
3、window.prompt => onJsPrompt
4、window.location => shouldOverrideUrlLoading
Android
JS向原生发消息 JavaScript 调用 Android 方法
第一种方法:弹窗的拦截
alert
confirm
prompt
举个例子:页面播放视频前判断手机使用的网络环境是WI-FI还是蜂窝网
原生应用拦截弹窗返回消息,这是同步的
异步怎么做?
原生代码如何执行JS告诉的回调方法?
定义回调方法,并请求
原生代码:在web页面注入js语句,获得window对象,调用回调方法(原生应用注入到JS中的代码)
第二种方法:URL拦截
通过schema方式,使用shouldOverrideUrlLoading方法对url协议进行解析。这种js的调用方式与ios的一样,使用iframe来调用native代码
URL请求被原生代码截获,去传输数据
对URL对定制:这是JS代码给我传递的消息,而不是真的页面跳转
协议、干什么、哪个回调方法
第三种方法:JSInterface
就是在页面的 window 对象里注入了 AndroidJS 对象。在js里可以直接调用
class JSInterface {
@JavascriptInterface //注意这个代码一定要加上
public String getUserData() {
return "UserData";
}
}
webView.addJavascriptInterface(new JSInterface(), "AndroidJS");
Native调用javascript方式
在android里是使用webview的loadUrl进行调用的,如:
// 调用js中的JSBridge.trigger方法
webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");
IOS
IOS 调用 JavaScript 方法
Native调用Javascript语言,是通过UIWebView组件的stringByEvaluatingJavaScriptFromString方法来实现的,该方法返回js脚本的执行结果。
在 IOS 中使用 stringByEvaluatingJavaScriptFromString 方法直接调用挂载在前端 window 下的方法,并获取方法返回的数据。
webview.stringByEvaluatingJavaScriptFromString("Math.random()")
从上面代码可以看出它其实就是调用了window下的一个对象,如果我们要让native来调用我们js写的方法,那这个方法就要在window下能访问到。但从全局考虑,我们只要暴露一个对象如JSBridge对native调用就好了,所以在这里可以对native的代码做一个简单的封装:
//下面为伪代码
webview.setDataToJs(somedata);
webview.setDataToJs = function(data) {
webview.stringByEvaluatingJavaScriptFromString("JSBridge.trigger(event, data)")
}
JavaScript 调用 IOS 方法
反过来,Javascript调用Native,并没有现成的API可以直接拿来用,而是需要间接地通过一些方法来实现。UIWebView有个特性:在UIWebView内发起的所有网络请求,都可以通过delegate函数在Native层得到通知。这样,我们就可以在UIWebView内发起一个自定义的网络请求,通常是这样的格式:jsbridge://methodName?param1=value1¶m2=value2
于是在UIWebView的delegate函数中,我们只要发现是jsbridge://开头的地址,就不进行内容的加载,转而执行相应的调用逻辑。
发起这样一个网络请求有两种方式:1. 通过localtion.href;2. 通过iframe方式; 通过location.href有个问题,就是如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。
使用iframe方式,以唤起Native APP的分享组件为例,简单如下:
在 JavaScript 中使用创建一个 iframe 请求 URL 的方式将带有 scheme 的 URL 传给 IOS
var url = 'jsbridge://doAction?title=分享标题&desc=分享描述&link=http%3A%2F%2Fwww.baidu.com';
var iframe = document.createElement('iframe');
iframe.style.width = '1px';
iframe.style.height = '1px';
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
setTimeout(function() {
iframe.remove();
}, 100);
IOS 在 WebView 获取到网页 URL 请求时将 scheme 码的 URL 拦截下来去做 native 方法的处理
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
print("shouldStartLoadWithRequest")
let url = request.URL
let scheme = url?.scheme
let method = url?.host
let query = url?.query
if url != nil && scheme == "jsbridge" {
print("scheme == \(scheme)")
print("method == \(method)")
print("query == \(query)")
switch method! {
case "getData":
self.getData()
case "putData":
self.putData()
case "gotoWebview":
self.gotoWebview()
case "gotoNative":
self.gotoNative()
case "doAction":
self.doAction()
case "configNative":
self.configNative()
default:
print("default")
}
return false
} else {
return true
}
}
项目通用方法抽象
在项目的实践中,我们逐渐抽象出一些通用的方法,这些方法基本上都是可以满足项目的需求。如下所示:
1.getData(datatype, callback, extra) H5从Native APP获取数据
使用场景:H5需要从Native APP获取某些数据的时候,可以调用这个方法。
JSBridge.getData('userInfo',function(data) {
console.log(data);
});