ios開發之--WKWebView的使用


WKWebView是ios 8 出來的,是為了解決UIWebView卡慢,占用內存過大的問題。

在以往時候,如果用UIWebView加載加載網頁的時候,卡慢現象會很嚴重,有時候往往會卡到一個頁面無法動彈,空白屏時間過長,基本上沒有什么體驗可言;

WebKit中的WKWebView控件的新特性和使用方法,較好的解決了卡、慢、占用內存過大的問題。而且支持了更多HTML5的特性,還有JS庫的加載和使用,功能比UIWebView強大了很多。

一、概述

如上圖所示,WebKit框架中最核心的類應該屬於WKWebView了,這個類專門用來渲染網頁視圖,其他類和協議都將基於它和服務於它。
WKWebView:網頁的渲染與展示,通過WKWebViewConfiguration可以進行自定義配置。
WKWebViewConfiguration:這個類專門用來配置WKWebView。
WKPreference:這個類用來進行相關webView設置。
WKProcessPool:這個類用來配置進程池,與網頁視圖的資源共享有關。
WKUserContentController:這個類主要用來做native與JavaScript的交互管理。
WKUserScript:用於進行JavaScript注入。
WKScriptMessageHandler:這個類專門用來處理JavaScript調用native的方法。
WKNavigationDelegate:網頁跳轉間的導航管理協議,這個協議可以監聽網頁的活動。
WKNavigationAction:網頁某個活動的示例化對象。
WKUIDelegate:用於交互處理JavaScript中的一些彈出框。
WKBackForwardList:堆棧管理的網頁列表。
WKBackForwardListItem:每個網頁節點對象。

 

二、相關的屬性

/// 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));

三、使用

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;

自定義配置
再WKWebView里面注冊供JS調用的方法,是通過WKUserContentController類下面的方法:

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

實現WKScriptMessageHandler協議方法

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
  // 判斷是否是調用原生的
   if ([@"NativeMethod" isEqualToString:message.name]) {
     // 判斷message的內容,然后做相應的操作
      if ([@"close" isEqualToString:message.body]) {

      }
   }
}

注意:上面將當前ViewController設置為MessageHandler之后需要在當前ViewController銷毀前將其移除,否則會造成內存泄漏。

[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"NativeMethod"];

四、WKNavigationDelegate代理方法

如果實現了代理方法,一定要在decidePolicyForNavigationAction和decidePolicyForNavigationResponse方法中的回調設置允許跳轉。

 

typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
WKNavigationActionPolicyCancel, // 取消跳轉
WKNavigationActionPolicyAllow, // 允許跳轉
} API_AVAILABLE(macosx(10.10), ios(8.0));
// 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(@"----------進程被終止時調用");
}

五、WKUIDelegate代理方法

/**
 *  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(@"----顯示一個文件上傳面板");

}

 

附:

官方文檔地址:https://developer.apple.com/documentation/webkit?language=objc 

美團技術團隊WebView性能、體驗分析與優化:https://tech.meituan.com/WebViewPerf.html?utm_source=tool.lu


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM