iOS 原生和JS交互总结

2018-12-09  本文已影响3人  魔都兰陵王

iOS 有两种 WebView, 一个是从iOS 2.0 开始加入的 UIWebView, 一个是从iOS 8.0 加入的 WKWebView.从性能和API 方面WKWebView 都比UIWebView 优秀,只是无法使用NSURLProtocol 进行URL 拦截过滤.

UIWebView 相关交互
1.通过shouldStartLoadWithRequest中拦截 url

NSString *requestString = request.URL.absoluteString;

1.JS 通过document.location 调用原生方法 setData:
function sendCommand(cmd, args) {
var url = "iosapp:" + cmd + ":" + args;
document.location = url;
}
sendCommand('setData', 'token'); // iosapp:setData:token

2.JS用打开一个iFrame的方式调用原生方法 load
function iframe(){
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", "load");
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
// 发起请求后这个 iFrame 就没用了,所以把它从 dom 上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}

2.通过 JavaScriptCore
在webViewDidFinishLoad方法中通过javaScriptContext ,将share 这个block桥接到JS, JS在使用时可以通过 share({}) 就能调用到share block 中的操作.
-(void)webViewDidFinishLoad:(UIWebView *)webView{
self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//添加js代用方法
self.jsContext[@"share"]= ^(){
NSArray *array = [JSContext currentArguments];
for (NSString *value in array) {
NSLog(@"收到js值:%@",value);
}
};
}

js 端代码
share({});

3.通过 JSExport
凡是实现JSExport 协议的对象,都可以 通过
jscontext[@"JS中实现了JSExport协议的实例别名"] = 实现了JSExport协议的实例,
如: self.jsContext[@"native"]= self;
这样JS 就可以简单的调用到 JSExport 协议中的原生方法 :
如 native.getMessage({});
@protocol JSObjcDelegate<JSExport>
-(void)getMessage:(id)msg;
@end

@interface WebViewController ()<UIWebViewDelegate, JSObjcDelegate>
-(void)webViewDidFinishLoad:(UIWebView )webView{
self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext[@"native"]= self;
//异常检查,当oc本地调用的js方法不存时,会打印异常信息
self.jsContext.exceptionHandler = ^(JSContext
context,JSValue *exceptionValue){
context.exception = exceptionValue;
NSLog(@"异常信息:%@", exceptionValue);
};
}

js 端代码
native.getMessage({});

OC 调用 JS
方式一
NSString *jsStr = [NSString stringWithFormat:@"jsGetValueFromOC('Hello world!')"];
[self.webView stringByEvaluatingJavaScriptFromString:jsStr];

方式二 通过使用JavaScriptCore
JSValue *callback = self.jsContext[@"jsGetValueFromOC"];
[callback callWithArguments:@[@"Hello world!"]];
或者
NSString *jsStr = @"jsGetValueFromOC('Hello world!')";
[self.jsContext evaluateScript:jsStr];

WKWebView 交互
WKWebView交互相对简单,API对于交互考虑的很全面
[config.userContentController addScriptMessageHandler:self name:@"share"]; 可以向JS 暴露原生方法
注意 在 controller dealloc 时候,需要 removeScriptMessageHandlerForName: 不然就会内存泄漏了.

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.preferences = [[WKPreferences alloc] init];
config.preferences.minimumFontSize = 10;
config.preferences.javaScriptEnabled = YES;
config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
config.userContentController = [[WKUserContentController alloc] init];
config.processPool = [[WKProcessPool alloc] init];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds
configuration:config];
//记得实现对应协议,不然方法不会实现.
self.webView.UIDelegate = self;
self.webView.navigationDelegate =self;
[self.view addSubview:self.webView];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.1.188/index1.html"]]];

// **************** 此处划重点 **************** //
//添加注入js方法, oc与js端对应实现
[config.userContentController addScriptMessageHandler:self  name:@"share"];
[config.userContentController addScriptMessageHandler:self  name:@"goBack"];

}

//js端代码
//window.webkit.messageHandlers.share.postMessage({ id: 'goodsId=1212'});

pragma mark - WKScriptMessageHandler

//实现js注入方法的协议方法

NSString * jsStr =[NSString stringWithFormat:@"sendKey('%@')",jsUserId];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
//此处可以打印error.
}];

上一篇下一篇

猜你喜欢

热点阅读