WKWebView是在Apple的WWDC 2014隨iOS 8和OS X 10.10出來的,是爲了解決UIWebView加載速度慢、佔用內存大的問題。
使用UIWebView加載網頁的時候,咱們會發現內存會無限增加,還有內存泄漏的問題存在。
WebKit中更新的WKWebView控件的新特性與使用方法,它很好的解決了UIWebView存在的內存、加載速度等諸多問題。java
在性能、穩定性、功能方面有很大提高(最直觀的體現就是加載網頁是佔用的內存);
容許JavaScript的Nitro庫加載並使用(UIWebView中限制);
支持了更多的HTML5特性;
高達60fps的滾動刷新率以及內置手勢;
將UIWebViewDelegate與UIWebView重構成了14類與3個協議查看蘋果官方文檔;ios
如上圖所示,WebKit框架中最核心的類應該屬於WKWebView了,這個類專門用來渲染網頁視圖,其餘類和協議都將基於它和服務於它。
WKWebView:網頁的渲染與展現,經過WKWebViewConfiguration能夠進行自定義配置。
WKWebViewConfiguration:這個類專門用來配置WKWebView。
WKPreference:這個類用來進行相關webView設置。
WKProcessPool:這個類用來配置進程池,與網頁視圖的資源共享有關。
WKUserContentController:這個類主要用來作native與JavaScript的交互管理。
WKUserScript:用於進行JavaScript注入。
WKScriptMessageHandler:這個類專門用來處理JavaScript調用native的方法。
WKNavigationDelegate:網頁跳轉間的導航管理協議,這個協議能夠監聽網頁的活動。
WKNavigationAction:網頁某個活動的示例化對象。
WKUIDelegate:用於交互處理JavaScript中的一些彈出框。
WKBackForwardList:堆棧管理的網頁列表。
WKBackForwardListItem:每一個網頁節點對象。web
/// webView的自定義配置 @property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration; /// 導航代理 @property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate; /// UI代理 @property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate; /// 訪問過網頁歷史列表 @property (nonatomic, readonly, strong) WKBackForwardList *backForwardList; /// 自定義初始化webView - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; /// url加載webView視圖 - (nullable WKNavigation *)loadRequest:(NSURLRequest *)request; /// 文件加載webView視圖 - (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0)); /// HTMLString字符串加載webView視圖 - (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL; /// NSData數據加載webView視圖 - (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0)); /// 返回上一個網頁節點 - (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item; /// 網頁的標題 @property (nullable, nonatomic, readonly, copy) NSString *title; /// 網頁的URL地址 @property (nullable, nonatomic, readonly, copy) NSURL *URL; /// 網頁是否正在加載 @property (nonatomic, readonly, getter=isLoading) BOOL loading; /// 加載的進度 範圍爲[0, 1] @property (nonatomic, readonly) double estimatedProgress; /// 網頁連接是否安全 @property (nonatomic, readonly) BOOL hasOnlySecureContent; /// 證書服務 @property (nonatomic, readonly, nullable) SecTrustRef serverTrust API_AVAILABLE(macosx(10.12), ios(10.0)); /// 是否能夠返回 @property (nonatomic, readonly) BOOL canGoBack; /// 是否能夠前進 @property (nonatomic, readonly) BOOL canGoForward; /// 返回到上一個網頁 - (nullable WKNavigation *)goBack; /// 前進到下一個網頁 - (nullable WKNavigation *)goForward; /// 從新加載 - (nullable WKNavigation *)reload; /// 忽略緩存 從新加載 - (nullable WKNavigation *)reloadFromOrigin; /// 中止加載 - (void)stopLoading; /// 執行JavaScript - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler; /// 是否容許左右滑動,返回-前進操做 默認是NO @property (nonatomic) BOOL allowsBackForwardNavigationGestures; /// 自定義代理字符串 @property (nullable, nonatomic, copy) NSString *customUserAgent API_AVAILABLE(macosx(10.11), ios(9.0)); /// 在iOS上默認爲NO,標識不容許連接預覽 @property (nonatomic) BOOL allowsLinkPreview API_AVAILABLE(macosx(10.11), ios(9.0)); /// 滾動視圖 @property (nonatomic, readonly, strong) UIScrollView *scrollView; /// 是否支持放大手勢,默認爲NO @property (nonatomic) BOOL allowsMagnification; /// 放大因子,默認爲1 @property (nonatomic) CGFloat magnification; /// 據設置的縮放因子來縮放頁面,並居中顯示結果在指定的點 - (void)setMagnification:(CGFloat)magnification centeredAtPoint:(CGPoint)point; /// 證書列表 @property (nonatomic, readonly, copy) NSArray *certificateChain API_DEPRECATED_WITH_REPLACEMENT("serverTrust", macosx(10.11, 10.12), ios(9.0, 10.0));
簡單使用,直接加載url地址macos
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://developer.apple.com/reference/webkit"]]]; [self.view addSubview:webView];
自定義配置
再WKWebView裏面註冊供JS調用的方法,是經過WKUserContentController類下面的方法:緩存
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;安全
// 建立配置 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; // 建立UserContentController(提供JavaScript向webView發送消息的方法) WKUserContentController* userContent = [[WKUserContentController alloc] init]; // 添加消息處理,注意:self指代的對象須要遵照WKScriptMessageHandler協議,結束時須要移除 [userContent addScriptMessageHandler:self name:@"NativeMethod"]; // 將UserConttentController設置到配置文件 config.userContentController = userContent; // 高端的自定義配置建立WKWebView WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config]; // 設置訪問的URL NSURL *url = [NSURL URLWithString:@"https://developer.apple.com/reference/webkit"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request]; [self.view addSubview:webView];
實現WKScriptMessageHandler協議方法服務器
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // 判斷是不是調用原生的 if ([@"NativeMethod" isEqualToString:message.name]) { // 判斷message的內容,而後作相應的操做 if ([@"close" isEqualToString:message.body]) { } } }
注意:上面將當前ViewController設置爲MessageHandler以後須要在當前ViewController銷燬前將其移除,不然會形成內存泄漏。app
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"NativeMethod"];
若是實現了代理方法,必定要在decidePolicyForNavigationAction和decidePolicyForNavigationResponse方法中的回調設置容許跳轉。框架
typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
WKNavigationActionPolicyCancel, // 取消跳轉
WKNavigationActionPolicyAllow, // 容許跳轉
} API_AVAILABLE(macosx(10.10), ios(8.0));ide
// 1 在發送請求以前,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSLog(@"1-------在發送請求以前,決定是否跳轉 -->%@",navigationAction.request); decisionHandler(WKNavigationActionPolicyAllow); } // 2 頁面開始加載時調用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"2-------頁面開始加載時調用"); } // 3 在收到響應後,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { /// 在收到服務器的響應頭,根據response相關信息,決定是否跳轉。decisionHandler必須調用,來決定是否跳轉,參數WKNavigationActionPolicyCancel取消跳轉,WKNavigationActionPolicyAllow容許跳轉 NSLog(@"3-------在收到響應後,決定是否跳轉"); decisionHandler(WKNavigationResponsePolicyAllow); } // 4 當內容開始返回時調用 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation { NSLog(@"4-------當內容開始返回時調用"); } // 5 頁面加載完成以後調用 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { NSLog(@"5-------頁面加載完成以後調用"); } // 6 頁面加載失敗時調用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"6-------頁面加載失敗時調用"); } // 接收到服務器跳轉請求以後調用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"-------接收到服務器跳轉請求以後調用"); } // 數據加載發生錯誤時調用 - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"----數據加載發生錯誤時調用"); } // 須要響應身份驗證時調用 一樣在block中須要傳入用戶身份憑證 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { //用戶身份信息 NSLog(@"----須要響應身份驗證時調用 一樣在block中須要傳入用戶身份憑證"); NSURLCredential *newCred = [NSURLCredential credentialWithUser:@"" password:@"" persistence:NSURLCredentialPersistenceNone]; // 爲 challenge 的發送方提供 credential [[challenge sender] useCredential:newCred forAuthenticationChallenge:challenge]; completionHandler(NSURLSessionAuthChallengeUseCredential,newCred); } // 進程被終止時調用 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { NSLog(@"----------進程被終止時調用"); }
/** * web界面中有彈出警告框時調用 * * @param webView 實現該代理的webview * @param message 警告框中的內容 * @param completionHandler 警告框消失調用 */ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler { NSLog(@"-------web界面中有彈出警告框時調用"); } // 建立新的webView時調用的方法 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { NSLog(@"-----建立新的webView時調用的方法"); return webView; } // 關閉webView時調用的方法 - (void)webViewDidClose:(WKWebView *)webView { NSLog(@"----關閉webView時調用的方法"); } // 下面這些方法是交互JavaScript的方法 // JavaScript調用confirm方法後回調的方法 confirm是js中的肯定框,須要在block中把用戶選擇的狀況傳遞進去 -(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler { NSLog(@"%@",message); completionHandler(YES); } // JavaScript調用prompt方法後回調的方法 prompt是js中的輸入框 須要在block中把用戶輸入的信息傳入 -(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{ NSLog(@"%@",prompt); completionHandler(@"123"); } // 默認預覽元素調用 - (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo { NSLog(@"-----默認預覽元素調用"); return YES; } // 返回一個視圖控制器將致使視圖控制器被顯示爲一個預覽。返回nil將WebKit的默認預覽的行爲。 - (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions { NSLog(@"----返回一個視圖控制器將致使視圖控制器被顯示爲一個預覽。返回nil將WebKit的默認預覽的行爲。"); return self; } // 容許應用程序向它建立的視圖控制器彈出 - (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController { NSLog(@"----容許應用程序向它建立的視圖控制器彈出"); } // 顯示一個文件上傳面板。completionhandler完成處理程序調用後打開面板已被撤銷。經過選擇的網址,若是用戶選擇肯定,不然爲零。若是不實現此方法,Web視圖將表現爲若是用戶選擇了取消按鈕。 - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler { NSLog(@"----顯示一個文件上傳面板"); }