WKWebView
1 在性能、穩(wěn)定性、功能方面有很大提升
2 和 Safari 相同的 JavaScript 引擎,允許JavaScript的Nitro庫加載并使用(UIWebView中限制);
WKWebView使用
// 創(chuàng)建webview
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
// 創(chuàng)建請求
NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
// 加載網(wǎng)頁
[webView loadRequest:request];
// 將webView添加到界面
[self.view addSubview:webView];
WKWebView操作JS
WKWebView加載JS
//JS文件路徑
NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];
//讀取JS文件內(nèi)容
NSString *jsContent = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil];
//創(chuàng)建用戶腳本對象,
//WKUserScriptInjectionTimeAtDocumentStart :HTML文檔創(chuàng)建后,完成加載前注入,類似于<head>中
//WKUserScriptInjectionTimeAtDocumentEnd :HTML文件完成加載后注入,類似于<body>中
WKUserScript *script = [[WKUserScript alloc] initWithSource:jsContent injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
//添加用戶腳本
[webView.configuration.userContentController addUserScript:script];
WKWebView執(zhí)行JS方法
//執(zhí)行JS方法
[webView evaluateJavaScript:@"test()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
//result為執(zhí)行js方法的返回值
if(error){
NSLog(@"Success");
}else{
NSLog(@"Fail");
}
}];
WKWebView代理方法
WKNavigationDelegate 協(xié)議 導(dǎo)航監(jiān)聽

WKNavigationDelegate
#pragma mark - WKNavigationDelegate
// 頁面開始加載時調(diào)用
#UIWebViewDelegate: - webView:shouldStartLoadWithRequest:navigationType
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
NSLog(@"%s",__FUNCTION__);
}
// 內(nèi)容開始返回時調(diào)用(view的過渡動畫可在此方法中加載)
#UIWebViewDelegate: - webViewDidStartLoad:
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
NSLog(@"%s",__FUNCTION__);
}
// 頁面加載完成時調(diào)用(view的過渡動畫的移除可在此方法中進行)
#UIWebViewDelegate: - webViewDidFinishLoad:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
NSLog(@"%s",__FUNCTION__);
}
// 頁面加載失敗時調(diào)用
#UIWebViewDelegate: - webView:didFailLoadWithError:
#WKNavigationDelegate: - webView:didFailNavigation:withError:
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"%s",__FUNCTION__);
}
三個頁面跳轉(zhuǎn)的代理方法:
#pragma mark WKNavigation 當web視圖需要響應(yīng)身份驗證跳轉(zhuǎn)時調(diào)用
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * credential))completionHandler{
}
#pragma mark 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
}
#pragma mark 在收到響應(yīng)后,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
}
#pragma mark 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
//需執(zhí)行decisionHandler的block。
}
Native調(diào)用JavaScript方法
原生調(diào)用JavaScript的代碼需要在頁面加載完成之后,就是在 - webView:didFinishNavigation:代理方法里面
OC代碼:
[webView evaluateJavaScript:@"showAlert('奏是一個彈框')" completionHandler:^(id item, NSError * _Nullable error) {
// Block中處理是否通過了或者執(zhí)行JS錯誤的代碼
}];
JavaScript調(diào)用Native方法
JavaScript的配置
window.webkit.messageHandlers.NativeMethod.postMessage("就是一個消息啊");
這個NativeMethod是和App中要統(tǒng)一的,配置方法將在下面的Native中書寫。
Native App的代碼配置
創(chuàng)建WKWebView除了有- initWithFrame:方法外,還有一個高端的方法:- initWithFrame:configuration:方法
// 創(chuàng)建配置
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 創(chuàng)建UserContentController(提供JavaScript向webView發(fā)送消息的方法)
WKUserContentController* userContent = [[WKUserContentController alloc] init];
// 添加消息處理,注意:self指代的對象需要遵守WKScriptMessageHandler協(xié)議,結(jié)束時需要移除
[userContent addScriptMessageHandler:self name:@"NativeMethod"];
// 將UserConttentController設(shè)置到配置文件
config.userContentController = userContent;
// 高端的自定義配置創(chuàng)建WKWebView
WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config];
// 設(shè)置訪問的URL
NSURL *url = [NSURL URLWithString:@"http://www.itdecent.cn"];
// 根據(jù)URL創(chuàng)建請求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// WKWebView加載請求
[webView loadRequest:request];
// 將WKWebView添加到視圖
[self.view addSubview:webView];
可以看到,添加消息處理的handler的name,就是JavaScript中調(diào)用時候的NativeMethod,這兩個要保持一致。請把URL換成你自己的。
請注意第6行的代碼配置當前ViewController為MessageHandler,需要服從WKScriptMessageHandler協(xié)議,如果出現(xiàn)警告??,請檢查是否服從了這個協(xié)議。
注意!注意!注意:上面將當前ViewController設(shè)置為MessageHandler之后需要在當前ViewController銷毀前將其移除,否則會造成內(nèi)存泄漏。
移除的代碼如下:
[webView.configuration.userContentController removeScriptMessageHandlerForName:@"NativeMethod"];
WKUIDelegate 協(xié)議 網(wǎng)頁監(jiān)聽

WKUIDelegate
#pragma mark - WKUIDelegate
/// 創(chuàng)建一個新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
return nil;
}
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler {
}
/// 輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
}
/// 確認框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
}
/// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
}
加載順序

百度測試
WKWebView增加的屬性
1 WKWebViewConfiguration *configuration:初始化WKWebView的時候的配置,后面會用到
2 WKBackForwardList *backForwardList:相當于訪問歷史的一個列表
3 double estimatedProgress:進度,有這個之后就不用自己寫假的進度條了
解決WKWebView加載POST請求無法發(fā)送參數(shù)問題
使用JavaScript解決WKWebView無法發(fā)送POST參數(shù)問題
1 將一個包含JavaScript的POST請求的HTML代碼放到工程目錄中
2 加載這個包含JavaScript的POST請求的代碼到WKWebView
3 加載完成之后,用Native調(diào)用JavaScript的POST方法并傳入?yún)?shù)來完成請求
- 創(chuàng)建包含JavaScript的POST請求的HTML代碼
<html>
<head>
<script>
//調(diào)用格式: post('URL', {"key": "value"});
function post(path, params) {
var method = "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
</script>
</head>
<body>
</body>
</html>
- 將對應(yīng)的JavaScript代碼通過加載本地網(wǎng)頁的形式加載到WKWebView
// JS發(fā)送POST的Flag,為真的時候會調(diào)用JS的POST方法(僅當?shù)谝淮蔚臅r候加載本地JS)
self.needLoadJSPOST = YES;
// 創(chuàng)建WKWebView
self.webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
//設(shè)置代理
self.webView.navigationDelegate = self;
// 獲取JS所在的路徑
NSString *path = [[NSBundle mainBundle] pathForResource:@"JSPOST" ofType:@"html"];
// 獲得html內(nèi)容
NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// 加載js
[self.webView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]];
// 將WKWebView添加到當前View
[self.view addSubview:self.webView];
- Native調(diào)用JavaScript腳本并傳入?yún)?shù)來完成POST請求
Native調(diào)用JavaScript
// 加載完成的代理方法
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
// 判斷是否需要加載(僅在第一次加載)
if (self.needLoadJSPOST) {
// 調(diào)用使用JS發(fā)送POST請求的方法
[self postRequestWithJS];
// 將Flag置為NO(后面就不需要加載了)
self.needLoadJSPOST = NO;
}
}
// 調(diào)用JS發(fā)送POST請求
- (void)postRequestWithJS {
// 發(fā)送POST的參數(shù)
NSString *postData = @"\"username\":\"aaa\",\"password\":\"123\"";
// 請求的頁面地址
NSString *urlStr = @"http://www.postexample.com";
// 拼裝成調(diào)用JavaScript的字符串
NSString *jscript = [NSString stringWithFormat:@"post('%@', {%@});", urlStr, postData];
// NSLog(@"Javascript: %@", jscript);
// 調(diào)用JS代碼
[self.webView evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) {
}];
}