WKWebView是蘋果在iOS 8之後推出的架構WebKit中的浏覽器控件,其加載速度比UIWebView快了許多, 但記憶體占用率卻下降很多,也解決了加載網頁時的記憶體洩露問題。現在的項目大多數隻需适配到iOS 8, 是以用WKWebView來替換項目中的UIWebView是很有必要的。
WKWebView常用到的幾個類:
- WKWebView
- WKWebViewConfiguration
- WKUserScript
- WKUserContentController
- WKWebsiteDataStore:清理緩存
以及3個代理:
- WKUIDelegate
- WKNavigationDelegate
- WKScriptMessageHandler
WKWebView常用屬性
WKUIDelegate 代理方法
這個代理方法, 主要是用來處理使用系統的彈框來替換JS中的一些彈框的,比如: 警告框, 選擇框, 輸入框, 主要使用的是下面三個代理方法:
// 建立一個新的WebView(标簽帶有 target='_blank' 時,導緻WKWebView無法加載點選後的網頁的問題。) - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { // 接口的作用是打開新視窗委托 WKFrameInfo *frameInfo = navigationAction.targetFrame; if (![frameInfo isMainFrame]) { [webView loadRequest:navigationAction.request]; } return nil; }
/** 警告框 在JS端調用alert函數時,會觸發此代理方法。 JS端調用alert時所傳的資料可以通過message拿到 在原生得到結果後,需要回調JS,是通過completionHandler回調 */ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { NSLog(@"%s", __FUNCTION__); UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:@"JS調用alert" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler(); }]]; [self presentViewController:alert animated:YES completion:NULL]; NSLog(@"%@", message); }
/** 确認框 JS端調用confirm函數時,會觸發此方法 通過message可以拿到JS端所傳的資料 在iOS端顯示原生alert得到YES/NO後 通過completionHandler回調給JS端 */ - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler { NSLog(@"%s", __FUNCTION__); UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS調用confirm" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler(YES); }]]; [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { completionHandler(NO); }]]; [self presentViewController:alert animated:YES completion:NULL]; NSLog(@"%@", message); }
/** 輸入框 JS端調用prompt函數時,會觸發此方法 要求輸入一段文本 在原生輸入得到文本内容後,通過completionHandler回調給JS */ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler { NSLog(@"%s", __FUNCTION__); NSLog(@"%@", prompt); UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS調用輸入框" preferredStyle:UIAlertControllerStyleAlert]; [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { textField.textColor = [UIColor redColor]; }]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler([[alert.textFields lastObject] text]); }]]; [self presentViewController:alert animated:YES completion:NULL]; }
WKNavigationDelegate代理方法
WKNavigationDelegate:最常用,和UIWebViewDelegate功能類似,該代理提供的方法,可以用來追蹤加載過程(頁面開始加載、加載完成、加載失敗)、決定是否執行跳轉。下面會對函數做簡單的說明,并用數字标出調用的先後次序:11-22-33-44-55。
用來追蹤加載過程(頁面開始加載、加載完成、加載失敗)的方法:
/**
* 22,頁面開始加載時調用
*
* @param webView 實作該代理的webview
* @param navigation 目前navigation
*/
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
/**
* 44,當内容開始傳回時調用
*
* @param webView 實作該代理的webview
* @param navigation 目前navigation
*/
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
/**
* 55,頁面加載完成之後調用
*
* @param webView 實作該代理的webview
* @param navigation 目前navigation
*/
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
/**
* 4,加載失敗時調用
*
* @param webView 實作該代理的webview
* @param navigation 目前navigation
* @param error 錯誤
*/
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"%s", __FUNCTION__);
}
頁面跳轉的代理方法:
/**
* 1,接收到伺服器跳轉請求之後調用
*
* @param webView 實作該代理的webview
* @param navigation 目前navigation
*/
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
/**
* 11,在發送請求之前,決定是否跳轉
*
* @param webView 實作該代理的
* @param navigationAction 目前navigation
* @param decisionHandler 是否調轉block
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *hostname = navigationAction.request.URL.host.lowercaseString;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated
&& ![hostname containsString:@".baidu.com"]) {
// 對于跨域,需要手動跳轉
[[UIApplication sharedApplication] openURL:navigationAction.request.URL];
// 不允許web内跳轉
decisionHandler(WKNavigationActionPolicyCancel);
} else {
self.progressView.alpha = 1.0;
decisionHandler(WKNavigationActionPolicyAllow);
}
NSLog(@"%s", __FUNCTION__);
}
/**
* 33,在收到響應後,決定是否跳轉。在收到伺服器的響應頭,根據response相關資訊,決定是否跳轉。decisionHandler必須調用,來決定是否跳轉,參數WKNavigationActionPolicyCancel取消跳轉,WKNavigationActionPolicyAllow允許跳轉。
*
* @param webView 實作該代理的webview
* @param navigationResponse 目前navigation
* @param decisionHandler 是否跳轉block
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
// NSLog(@"%@",navigationResponse.response);
// 如果響應的位址是百度,則允許跳轉
// if ([navigationResponse.response.URL.host.lowercaseString isEqual:@"www.baidu.com"]) {
//
// // 允許跳轉
// decisionHandler(WKNavigationResponsePolicyAllow);
// return;
// }
// // 不允許跳轉
// decisionHandler(WKNavigationResponsePolicyCancel);
decisionHandler(WKNavigationResponsePolicyAllow);
}
其他一些方法
// 當main frame最後下載下傳資料失敗時,會回調
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
}
// 用于授權驗證的API,與AFN、UIWebView的授權驗證API是一樣的
// 對于HTTPS的都會觸發此代理,如果不要求驗證,傳預設就行
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler{
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling ,nil);
}
/**
9.0才能使用,web内容進行中斷時會觸發
當web content處理完成時,會回調
在 UIWebView 上當記憶體占用太大的時候,App Process 會 crash,在 WKWebView 上當總體的記憶體占用比較大的時候,WebContent Process 會 crash,進而出現白屏現象。
iOS 9以後 WKNavigtionDelegate 新增了一個回調函數:
*/
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
[webView reload];
NSLog(@"程序終止");
}
WKWebView 執行JS代碼
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSString *jsString = [NSString stringWithFormat:@"showSatisfaction()"]; [self.wkWebView evaluateJavaScript:jsString completionHandler:^(id response, NSError * error) { NSLog(@"error: %@", error.description); NSLog(@"response: %@", response); //js傳回0:js控制跳出彈框 1:傳回上級頁面 if ([response intValue] == 1) { [self.navigationController popViewControllerAnimated:YES]; } }]; });
WKScriptMessageHandler代理方法
WKScriptMessage有兩個關鍵屬性name 和 body。因為我們給每一個OC方法取了一個name,是以就可以根據name 來區分執行不同的方法。body 中存着JS 要給OC 傳的參數。// 從web界面中接收到一個腳本時調用 -(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ //JS調用OC方法 //message.boby就是JS裡傳過來的參數 NSLog(@"body:%@",message.body); if ([message.name isEqualToString:@"Share"]) { [self ShareWithInformation:message.body]; } else if ([message.name isEqualToString:@"Camera"]) { [self camera]; } }
-(void)ShareWithInformation:(NSDictionary *)dic{ if (![dic isKindOfClass:[NSDictionary class]]) { return; } NSString *title = [dic objectForKey:@"title"]; NSString *content = [dic objectForKey:@"content"]; NSString *url = [dic objectForKey:@"url"]; //在這裡寫分享操作的代碼 NSLog(@"要分享了哦?"); //OC回報給JS分享結果 NSString *JSResult = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; //OC調用JS [self.webView evaluateJavaScript:JSResult completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@", error); }]; }
相關文章
[iOS]WKWebView的使用--API篇
UIWebView、WKWebView使用詳解及性能分析
iOS WKWebView的基本使用
iOS WKWebView(清理緩存)
iOS OC與JS的互動(WKWebview-MessageHandler實作)