-
Notifications
You must be signed in to change notification settings - Fork 52
jsbridge原理
在android里执行比较简单:
String call = "javascript:alert('hello')";
webView.loadUrl(call);
android4.4以后,可以使用evaluateJavascript
直接执行,可以很方便地获取到js的返回值
private void testEvaluateJavascript(WebView webView) {
webView.evaluateJavascript("hello()", new ValueCallback<String>() {
@override
public void onReceiveValue(String value) {
System.out.println("onReceiveValue = " + value)
}
})
}
IOS下这样执行
NSString *currentURL = [webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
ji
修改location.href
,在IOS和android里设置location.href
,会分别被shouldStartLoadWithRequest(iOS)
和shouldOverrideUrlLoading(andoroid)
获取到,处理完成以后可以告诉webview这不是真正的url转跳。
js和native可以约定好一个协议,url里包含js要传递的信息,调用的api的信息、参数、回调函数名,然后通过location.href
设置,native拦截以后处理完信息告诉webview不进行跳转
另外,修改location.hash
也可以
js可以把需要native执行的回调挂载window下,然后native在处理完以后,把要返回的数据通过执行window下的回调传递给js,然后js移除掉window下的函数即可
这里的回调都是异步的
如果要同步执行,可以插入一个看不见的iframe,然后设置iframe的src,同样可以被native拦截到。拦截之后利用了webview的undocumented
特性,他会保证在shouldStartLoadWithRequest(IOS)
和shouldOverrideUrlLoading(Android)
处理完之前,阻塞当前js的执行,等处理完成以后,在继续执行js
iframe比直接修改父页面的location更加适合开发,通常都采用这种方式
object-c还可以完成js方法和变量注入
NSString *network = @"'wifi'";
NSString *javascriptCommand = @"function test(){ return 'ok' };var network ="; javascriptCommand = [javascriptCommand stringByAppendingString:network]; [webview stringByEvaluatingJavascriptFromString:javascriptCommand];
这样js就可以使用test方法和network变量
Android下注入js对象的方法
最早的是偶这种方式在android下很方便,把一个java对象暴露给javascript,可以让javascript直接调用Java的方法。
mWebView.getSettings().setJavascriptEnabled(true); mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
然后这个方法并不好用,主要问题是安全问题,在android4.2以前,这个防范存在注入的漏洞
利用java的反射机制,可以实现在webview里执行命令,然后通过一系列的恶意命令做坏事
funcrion execute(amdArgs) { return jsInterface.getClass().forName("java.lang.Runtime").getMethod("getRuntime", null).invoke(null, null).exec(cmdArgs); }
android4.2以后只有申明@javascriptinterface的方法才可以被js调用
andorid下安全又好用又兼容的方法
在js里,alert confirm prompt这几个方法都会对应到webChromeClient中的方法,prompt这个方法几乎没人用了,可以用来和native进行交互
可以重载一下webChromeClient的onJSPrompt方法就可以了
bt的bridge,在安卓下就是用的prompt,ios上也可以这么用,但是需要扩展UIwebview类
jsbridge的功能就是把所有和native通讯的代码封装,然后提供api给前端开发同学使用,已bt的bridge为例,ios里js是通过创建iframe之后设置src来通讯的,android里是通过prompt方法进行通信的,然后native通过执行暴露的>两个方法执行回调
onSuccess: function(sid, data) { // native代码处理成功后,调用该防范来通知js WV_Private.onComplete(sid, data, 'success'); },
onFailure: function(sid, data) { // native代码处理失败后,调用该方法通知js WV_Private.onComplete(sid, data, 'failure'); }
当native要主动向js传递信息的时候,他会通过执行js里的方法注册一个事件并触发,然后js就可以得到返回的数据了
fireEvent: function(eventname, eventdata, sid) { // 当native需要通知js的时候(通信),用触发事件的方式进行 var ev = doc.createEvent('HTMLEvents'); ev.initEvent(eventname, false, true); ev.param = WV_Private.parseData(eventdata) || WV_Private.getData(sid); doc.dispatchEvent(ev); // doc = document }
基本上实现了上面的通信过程之后,只要native按照规范提供接口,就可以方便的开发了(当然还有其他的小问题需要处理,例如iframe的管理等)
function ready(callback) { if (window.jsBridge) { callback && callback() } else { document.addEventListener('jsbridgeReady', callback, false) }
}
ready(function(){ jsBridge.call('toast', { content: 'hello' }) })
import jsBridge from 'jsBridge'
jsBridge.toast('网络不给力,请稍后再试')