前言: 根據(jù)需求有時候需要用到JS與Objective-C交互來實現(xiàn)一些功能, 本文介紹實現(xiàn)交互的一種方式, 使用WKWebView的新特性MessageHandler, 來實現(xiàn)JS調(diào)用原生, 原生調(diào)用JS.
一. 基礎(chǔ)說明
WKWebView 初始化時,有一個參數(shù)叫configuration,它是WKWebViewConfiguration類型的參數(shù),而WKWebViewConfiguration有一個屬性叫userContentController,它又是WKUserContentController類型的參數(shù)。WKUserContentController對象有一個方法- addScriptMessageHandler:name:,我把這個功能簡稱為MessageHandler。- addScriptMessageHandler:name:有兩個參數(shù),第一個參數(shù)是userContentController的代理對象,第二個參數(shù)是JS里發(fā)送postMessage的對象。
所以要使用MessageHandler功能,就必須要實現(xiàn)WKScriptMessageHandler協(xié)議。
二. 在JS中使用方法

- js文件代碼實例
function locationClick() {
/// "showMessage". 為我們和前端開發(fā)人員的約定
window.webkit.messageHandlers.showMessage.postMessage(null);
}
- 在ViewController 我們需要做哪些事情
2.1 對WKWebView進行初始化以及設(shè)置
/// 創(chuàng)建網(wǎng)頁配置對象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
/// 創(chuàng)建設(shè)置對象
WKPreferences *preference = [[WKPreferences alloc]init];
/// 最小字體大小 當將javaScriptEnabled屬性設(shè)置為NO時,可以看到明顯的效果
preference.minimumFontSize = 40.0;
/// 設(shè)置是否支持javaScript 默認是支持的
preference.javaScriptEnabled = YES;
/// 在iOS上默認為NO,表示是否允許不經(jīng)過用戶交互由javaScript自動打開窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
/// 這個類主要用來做native與JavaScript的交互管理
_wkwebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) configuration:config];
[self.view addSubview:_wkwebView];
/// Load WebView
#if 0
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://m.benlai.com/huanan/zt/1231cherry"]];
[self.wkwebView loadRequest:request];
#endif
#if 1
NSString *bundleStr = [[NSBundle mainBundle] pathForResource:@"summerxx-test" ofType:@"html"];
[self.wkwebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:bundleStr]]];
#endif
// UI代理
_wkwebView.UIDelegate = self;
// 導航代理
_wkwebView.navigationDelegate = self;
// 是否允許手勢左滑返回上一級, 類似導航控制的左滑返回
_wkwebView.allowsBackForwardNavigationGestures = YES;
// 添加監(jiān)測網(wǎng)頁加載進度的觀察者
[self.wkwebView addObserver:self
forKeyPath:@"estimatedProgress"
options:0
context:nil];
// 添加監(jiān)測網(wǎng)頁標題title的觀察者
[self.wkwebView addObserver:self
forKeyPath:@"title"
options:NSKeyValueObservingOptionNew
context:nil];
2.2 在合理地方進行注冊
[self.wkwebView.configuration.userContentController addScriptMessageHandler:self name:@"showMessage"];
2.3 接收JS給我們傳遞消息, 這里我做了一個簡單的彈窗提示
#pragma mark - WKScriptMessageHandler
/// 通過接收JS傳出消息的name進行捕捉的回調(diào)方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([message.name isEqualToString:@"showMessage"]) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"title" message:@"messgae" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"同意" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"雖然我同意了你, 但是答應我別驕傲."];
[self.wkwebView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"cancel");
}];
UIAlertAction *errorAction = [UIAlertAction actionWithTitle:@"拒絕" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"雖然我拒絕了你, 但是繼續(xù)愛我好嗎"];
[self.wkwebView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}];
[alertController addAction:errorAction];
[alertController addAction:okAction];
[alertController addAction:cancelAction];
// 出現(xiàn)
[self presentViewController:alertController animated:YES completion:^{
}];
}
}
2.3 銷毀
- (void)dealloc {
/// Remove removeObserver
[_wkwebView removeObserver:self
forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
[_wkwebView removeObserver:self
forKeyPath:NSStringFromSelector(@selector(title))];
WKUserContentController *userCC = self.wkwebView.configuration.userContentController;
[userCC removeScriptMessageHandlerForName:@"showMessage"];
}
Demo: 演示步驟, 點擊獲取定位 Objective-C獲取到JS消息
點擊拒絕, JS獲取到Objective-C傳遞的消息
如圖:


總結(jié): 腦殼疼
備注: 如果遇到跨域問題, 主要還是前端和服務端改一下就好了.
參照 : http://www.itdecent.cn/p/433e59c5a9eb
demo: https://github.com/summerxx27/JS_ObjectiveC_MessageHandler
完~
文/夏天然后