使用WKWebView的時(shí)候,如果想要實(shí)現(xiàn)JS調(diào)用OC方法,除了攔截URL之外,還有一種簡單的方式。那就是利用WKWebView的新特性MessageHandler來實(shí)現(xiàn)JS調(diào)用原生方法。
MessageHandler 是什么?
WKWebView 初始化時(shí),有一個(gè)參數(shù)叫configuration,它是WKWebViewConfiguration類型的參數(shù),而WKWebViewConfiguration有一個(gè)屬性叫userContentController,它又是WKUserContentController類型的參數(shù)。WKUserContentController對象有一個(gè)方法- addScriptMessageHandler:name:,我把這個(gè)功能簡稱為MessageHandler。
- addScriptMessageHandler:name:有兩個(gè)參數(shù),第一個(gè)參數(shù)是userContentController的代理對象,第二個(gè)參數(shù)是JS里發(fā)送postMessage的對象。 所以要使用MessageHandler功能,就必須要實(shí)現(xiàn)WKScriptMessageHandler協(xié)議。 我們在該API的描述里可以看到在JS中的使用方法:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
//其中<name>,就是上面方法里的第二個(gè)參數(shù)`name`。
//例如我們調(diào)用API的時(shí)候第二個(gè)參數(shù)填@"Share",那么在JS里就是:
//window.webkit.messageHandlers.Share.postMessage(<messageBody>)
//<messageBody>是一個(gè)鍵值對,鍵是body,值可以有多種類型的參數(shù)。
// 在`WKScriptMessageHandler`協(xié)議中,我們可以看到mssage是`WKScriptMessage`類型,有一個(gè)屬性叫body。
// 而注釋里寫明了body 的類型:
Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.
MessageHandler的使用
// 這是創(chuàng)建configuration 的過程
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 40.0;
configuration.preferences = preferences;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// addScriptMessageHandler 很容易導(dǎo)致循環(huán)引用
// 控制器 強(qiáng)引用了WKWebView,WKWebView copy(強(qiáng)引用了)configuration, configuration copy (強(qiáng)引用了)userContentController
// userContentController 強(qiáng)引用了 self (控制器)
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"GoBack"];
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
}
//需要注意的是addScriptMessageHandler很容易引起循環(huán)引用,導(dǎo)致控制器無法被釋放,所以需要加入以下這段:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 因此這里要記得移除handlers
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Shake"];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"GoBack"];
}
WKScriptMessageHandler的代理實(shí)現(xiàn)
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
if ([message.name isEqualToString:@"Shake"]) {
NSLog(@"分享");
} else if ([message.name isEqualToString:@"GoBack"]) {
NSLog(@"返回");
}
}
JS調(diào)iOS原生方法
const u = navigator.userAgent;
//android終端
const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
// IOS終端
const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isiOS) {<!-- -->
window.webkit.messageHandlers.GoBack.postMessage('');//getUserId.postMessage('')為IOS定義的原生方法
//你的邏輯代碼
} else if (isAndroid) {<!-- -->
window.java_obj.GoBack() //java_obj.getUserId()為安卓定義的方法,具體方法名可與其溝通
// 你的邏輯代碼
}