背景
随着H5功能愈发的强大,混合开发势在必行,其中涉及的原生与JS的交互逻辑如何设定就成了当务之急。
之前的方案
1.通过URL截取方法名和参数方式(缺点:截取麻烦)
2.运用JavaScriptCore框架,通过JSContenxt对象注入方法(缺点:页面重定向后需要重新注入)
3.舍弃UIWebView,采用WKWebView,新容器提供js与原生互调方法userContentController:didReceiveScriptMessage:方法(缺点:见通病)
这三种方案通病:当js调用native时,有时需要通过回调来获取相应的信息,然上述三种方法均不可实现。
现行方案
js端
/*************iOS原生与web交互相关事件***************/
var DQSBridgeEvent = {
_listeners : {},
addEvent : function(type, fn) {
if (typeof this._listeners[type] === "undefined") {
this._listeners[type] = [];
}
if (typeof fn === "function") {
this._listeners[type].push(fn);
}
return this;
},
fireEvent : function(type, param) {
var arrayEvent = this._listeners[type];
if (arrayEvent instanceof Array) {
for (var i = 0, length = arrayEvent.length; i < length; i += 1) {
if (typeof arrayEvent[i] === "function") {
arrayEvent[i](param);
}
}
}
return this;
},
removeEvent : function(type, fn) {
var arrayEvent = this._listeners[type];
if (typeof type === "string" && arrayEvent instanceof Array) {
if (typeof fn === "function") {
for (var i = 0, length = arrayEvent.length; i < length; i += 1) {
if (arrayEvent[i] === fn) {
this._listeners[type].splice(i, 1);
break;
}
}
} else {
delete this._listeners[type];
}
}
return this;
}
};
var DQSEventHandler = {
//方法调用
callNativeFunction : function(nativeMethodName, params, callBackID, callBack) {
var message;
if (!callBack) {
message = {
'methodName' : nativeMethodName,
'params' : params
};
window.webkit.messageHandlers.DQSEventHandler.postMessage(message);
} else {
message = {
'methodName' : nativeMethodName,
'params' : params,
'callBackID' : callBackID
};
if (!DQSBridgeEvent._listeners[callBackID]) {
DQSBridgeEvent.addEvent(callBackID, function(data) {
callBack(data);
});
}
window.webkit.messageHandlers.DQSEventHandler.postMessage(message);
}
},
//执行js回调
callBack : function(callBackID, data) {
DQSBridgeEvent.fireEvent(callBackID, data);
},
//删除所有交互方法
removeAllCallBacks : function(data) {
DQSBridgeEvent._listeners = {};
}
};
//测试调用(js调用native)
DQSEventHandler.callNativeFunction("judgeLogin", null, "judgeLoginCallBack", function(token){
if (token == "" || token == null) {
//未登录逻辑处理!
alert("未登录");
} else {
//已登录逻辑处理!
alert("已登录");
}
});
Objective-C端
//注册js与原生交互对象
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"DQSEventHandler"];
//js调用native
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"DQSEventHandler"]) {
NSString *methodName = message.body[@"methodName"];
NSDictionary *params = message.body[@"params"];
NSString *callBackId = message.body[@"callBackID"];
//根据方法名和回调ID来进行相应处理
...
//测试
if ([methodName isEqualToString:@"judgeLogin"]) {
[self judgeLogin:^(response) {
NSString *js = [NSString stringWithFormat:@"DQSEventHandler.callBack('%@','%@');",callBackId,response];
[self.webView evaluateJavaScript:js completionHandler:NULL];
}];
}
}
}
//native调用js
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
NSString *js = @"";
[webView evaluateJavaScript:js completionHandler:^(id response, NSError * _Nullable error) {
}];
}
//注销js与原生交互事件
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"DQSEventHandler"];
[self.webView evaluateJavaScript:@"DQSEventHandler.removeAllCallBacks()" completionHandler:NULL];
//测试调用
- (void)judgeLogin:(void(^)(id response))callBack{
NSString *token = @"";
if(callBack){
callBack(token);
}
}