效果
项目地址
UIWebView与JS的深度交互
事情的起因还是因为项目需求驱动。折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾。
参考 Github上看到了WebViewJavascriptBridge 这个用于UIWebView/WebViews和JS交互的封装库。
- 一开始,我们在Native端和JS端都分别进行初始化:
- OC端:
@property WebViewJavascriptBridge* bridge;
对应的初始化代码如下,在初始化中直接包含了一个用于接收JS的回调:
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC received message from JS: %@", data);
responseCallback(@"Response for message from ObjC");
}];
- JS端:(以下是固定写法,你自己的JS文件中必须包含如下代码)
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener('WebViewJavascriptBridgeReady', function() {
callback(WebViewJavascriptBridge)
}, false)
}
}
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
log('JS got a message', message)
var data = { 'Javascript Responds':'Wee!' }
log('JS responding with', data)
responseCallback(data)
})
}
-
同理,第二条,在JS中调用了bridge.callHandler('testJavascriptHandler'),它将触发OC端注册的同名方法:
原理图
以上表中的对应关系的解读是,例如第一条:在JS中如果调用了bridge.send(),那么将触发OC端_bridge初始化方法中的回调。
同理,第二条,在JS中调用了bridge.callHandler('testJavascriptHandler'),它将触发OC端注册的同名方法:
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
了解了使用规则,下面来看看在我们这个实际需求中应用的整体思路:

基于以上的思路,使用vue实现 和 webview的交互
- 原生调用vue中的方法
由于vue中作用域的关系,所以交互的事件必须挂载到window上,那么实现思路就是写一个vue的plugin(插件),并且把这个插件对象挂载到window上,代码如下:
```
var hybrid = {
install (Vue, options) {
// 把当前的对象挂载到vue的全局
Vue.prototype.$hybrid = this;
}
}
// 把vue中绑定的对象挂载到window上
window.Hybrid = hybrid;
// 导出共给vue组件中引入使用
export default hybrid
```
###android 中执行调用:
```
webView.loadUrl("javascript:Hybrid.registerHandler('android', 'jsActivityShare')");
```
###ios 中执行:
```
// 方法一. JSValue *function = [self.context objectForKeyedSubscript:@"factorial"];
// 方法二.
JSValue * function = self.context[@"factorial"];
JSValue *result = [function callWithArguments:@[inputNumber]];
self.showLable.text = [NSString stringWithFormat:@"%@", [result toNumber]];
```
-
vue中的方法调原生
需求:实现一个处理原生的数据 然后回掉原生方法, 代码如下:
// 注册原生发过来的方法,name需要注册的方法的名字 registerHandler (name, callBack) { console.log(name + "js 处理原生发送的数据"); try { // eval(this.native.callBack) 必须指定清楚那个对象的函数名字 if (typeof(eval(this.native.callBack)) == "function") { eval("this.native." + callBack + "('js处理完成之后的结果回传给原生客户端');"); } else { // 函数不存在, 抛出异常提示函数不存在 alert(callBack); } }catch(err){ alert(err) // 可执行 } }
-
原生调用vue组件中的函数
需要使用vue的广播事件,在vue的全局挂载一个事件对象,然后由这个事件对象统一处理事件,代码如下:
Vue.prototype.$eventHub= Vue.prototype.$eventHub || new Vue({data:{'message':''}, template:'<div> {{message}} </ div>'}); this.$eventHub = Vue.prototype.$eventHub;
然后发送广播事件
//调用$emit 方法, 来发送全局的函数 this.$eventHub.$emit('event', yourData);
最后在组件中接受广播事件
// 监听app中发出的事件 this.$eventHub.$on('event', (index)=>{ TODO:: // 调用组件内容函数处理 });
参考:
网友评论