最近因為公司的項目要大量用到H5,公司的適配版本也終于提到了iOS8以上,所以是時候換掉陳舊的UIWebView了。用這篇文章來總結一下最近用到的WKWebView相關知識,歡迎各位留言指正交流。
WKWebView的創建
- (WKWebView *)webView {
if (!_webView) {
//初始化WKWebViewConfiguration
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
/**
設置代理對象
ScriptMessageHandler:WKScriptMessageHandler的代理對象
name:跟后端協調好的響應名稱
**/
[config.userContentController addScriptMessageHandler:self name:@"methodName"];
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 64) configuration:config];
[_webView loadRequest:[ NSURLRequest requestWithURL:url]];
_webView.navigationDelegate = self;
}
return _webView;
}
在這段代碼中,我們設置了兩個代理,所以應該遵守代理協議,分別是WKNavigationDelegate和WKScriptMessageHandler,兩個代理方法的具體實現會在下文進行說明。這里特別說明WKScriptMessageHandler代理對象的設置并不是使用點語法的形式,而是在初始化webView的時候先初始化WKWebViewConfiguration類型的對象config,然后使用- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration方法設置代理。
WKNavigationDelegate
這個代理我用到的代理方法比較簡單有三個如下,其他的代理方法也有很多文章進行說明,我就不再贅述。
// 頁面開始加載時調用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}
// 頁面加載完成之后調用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
}
// 頁面加載失敗時調用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation {
}
WKScriptMessageHandler(JS調用原生)
在看這個代理方法之前,我們首先回顧一下webView的創建時調用的一句代碼
[config.userContentController addScriptMessageHandler:self name:@"methodName"];
在創建config對象時,我們給他綁定一個名為methodName的方法,而這個方法就是和H5同事協定好的用來交互的方法的方法名,里面可以通過傳參來確定接下來進行何種交互,而交互的代碼就寫在代理方法里面,接下來看看代理方法。
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
NSString *messageStr = [NSString stringWithFormat:@"%@",message.body];
}
這里的message是js調用methodName方法回傳的信息,我們可以在代理方法中通過解析message得到和H5協定好的特殊標識來進行交互。當然你必須在js的代碼中寫如下代碼才能保證交互成功(PS:這是H5中的JS代碼)。
window.webkit.messageHandlers. methodName.postMessage()
我個人認為這樣的交互方式其實跟UIWebView通過截取字符串的交互方式有些類似,都是通過和前端協定好的特殊標識符來執行所對應的交互內容,舉個例子,一個H5中有兩個按鈕,點擊第一個按鈕跳轉控制器A,第二個按鈕跳轉控制器B,那H5人員在處理按鈕A和B的交互事件的地方分別寫下如下代碼
window.webkit.messageHandlers. methodName.postMessage(pushVcA)
window.webkit.messageHandlers. methodName.postMessage(pushVcB)
我們iOS端在代理方法中寫下如下代碼
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
NSString *messageStr = [NSString stringWithFormat:@"%@",message.body];
if (messageStr isEqualToString:@"pushVcA") {
//跳轉控制器A
}
if (messageStr isEqualToString:@"pushVcB") {
//跳轉控制器B
}
}
這只是一個簡單的交互場景舉例,但是JS調用原生方法就是在這個代理方法中實現。接下來講一下原生如何調用JS方法。
原生調用JS
原生調用JS需要用到WKWebView的方法
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler
我的使用方式為
NSString *startStr = @"startUploadImgCB('start')";
[self.webView evaluateJavaScript:startStr completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"value: %@ error: %@", response, error);
}];
結合我的使用場景來進行一下說明,我這里的H5需要調用原生相冊和拍照進行圖片上傳,我的代碼是寫在上傳開始前的地方,這里的startUploadImgCB即為JS寫好的方法,start是我傳給JS的參數,目的是告訴JS原生開始上傳圖片,開始上傳動畫。注意這個方法要跟上文中約定好的交互方法methodName方法區分開,methodName是JS調用原生的方法名,而startUploadImgCB是原生調用JS的方法名。
以上就是對本次項目中所用到的原生與H5交互知識的總結,demo需要H5端的配合就不上了,本人才疏學淺,如果有不對的地方煩請各路大神指正,歡迎大家交流!