WKWebView - API梳理

WKWebView介紹

主要類:

  • WKWebView
  • WKWebViewConfiguration:
  • WKUserScript:
  • WKUserContentController:
  • WKWebsiteDataStore:

主要代理:

  • WKNavigationDelegate
  • WKUIDelegate

1. WKWebView

1.1 常用屬性

// 導(dǎo)航代理
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
// UI代理
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;

// 頁面標(biāo)題, 一般使用KVO動態(tài)獲取
@property (nullable, nonatomic, readonly, copy) NSString *title;
// 頁面加載進(jìn)度, 一般使用KVO動態(tài)獲取
@property (nonatomic, readonly) double estimatedProgress;

// 可返回的頁面列表, 已打開過的網(wǎng)頁, 有點(diǎn)類似于navigationController的viewControllers屬性
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;

// 頁面url
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
// 頁面是否在加載中
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
// 是否可返回
@property (nonatomic, readonly) BOOL canGoBack;
// 是否可向前
@property (nonatomic, readonly) BOOL canGoForward;
// WKWebView繼承自UIView, 所以如果想設(shè)置scrollView的一些屬性, 需要對此屬性進(jìn)行配置
@property (nonatomic, readonly, strong) UIScrollView *scrollView;
// 是否允許手勢左滑返回上一級, 類似導(dǎo)航控制的左滑返回
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;

//自定義UserAgent, 會覆蓋默認(rèn)的值 ,iOS 9之后有效
@property (nullable, nonatomic, copy) NSString *customUserAgent

1.2 常用方法

// 帶配置信息的初始化方法
// configuration 配置信息
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
// 加載請求
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
// 加載HTML
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
// 返回上一級
- (nullable WKNavigation *)goBack;
// 前進(jìn)下一級, 需要曾經(jīng)打開過, 才能前進(jìn)
- (nullable WKNavigation *)goForward;
// 刷新頁面
- (nullable WKNavigation *)reload;
// 根據(jù)緩存有效期來刷新頁面
- (nullable WKNavigation *)reloadFromOrigin;
// 停止加載頁面
- (void)stopLoading;
// 執(zhí)行JavaScript代碼
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

2. WKWebViewConfiguration

網(wǎng)頁配置模型,僅在初始化時可設(shè)置,初始化后無法修改。

/*webview的進(jìn)程池,與頁面的資源存儲有關(guān)
Tips:前端使用 localstorage 進(jìn)行存儲,A頁面和B頁面都存在 一個WKWebView,在B頁面使用localstorage保存信息,回到A頁面取不到最新的數(shù)據(jù)。
解決方案:將processPool設(shè)置成單例。
*/
@property (nonatomic, strong) WKProcessPool *processPool;
// webview 偏好設(shè)置,可設(shè)置最小字體等屬性
@property (nonatomic, strong) WKPreferences *preferences;
// 專門用來管理native與JavaScript的交互行為
@property (nonatomic, strong) WKUserContentController *userContentController;
// web持久化,包括 cookie、磁盤和內(nèi)存緩存以及持久性數(shù)據(jù),例如 WebSQL、IndexedDB 數(shù)據(jù)庫和本地存儲
@property (nonatomic, strong) WKWebsiteDataStore *websiteDataStore API_AVAILABLE(macos(10.11), ios(9.0));
// 是否在所有的數(shù)據(jù)加載到內(nèi)存中才開始渲染,默認(rèn)為 NO。加載網(wǎng)頁時,網(wǎng)頁會逐漸呈現(xiàn),設(shè)置為true,僅在加載所有內(nèi)容后才顯示網(wǎng)頁。
@property (nonatomic) BOOL suppressesIncrementalRendering;
// 設(shè)置User-Agent最后的名字,用于標(biāo)記應(yīng)用。
@property (nullable, nonatomic, copy) NSString *applicationNameForUserAgent API_AVAILABLE(macos(10.11), ios(9.0));
// 是否允許播放媒體文件,默認(rèn)為YES
@property (nonatomic) BOOL allowsAirPlayForMediaPlayback API_AVAILABLE(macos(10.11), ios(9.0));
// 指對已知支持 HTTPS 的服務(wù)器的 HTTP 請求是否應(yīng)自動升級為 HTTPS 請求。默認(rèn)為YES
@property (nonatomic) BOOL upgradeKnownHostsToHTTPS API_AVAILABLE(macos(11.3), ios(14.5));
// 網(wǎng)頁中的多媒體是否需要手勢才能開始播放(iOS 10) 可以設(shè)置僅音頻需要、僅視頻需要等四種狀態(tài)
@property (nonatomic) WKAudiovisualMediaTypes mediaTypesRequiringUserActionForPlayback API_AVAILABLE(macos(10.12), ios(10.0));
// 決定了用內(nèi)嵌HTML5播放視頻還是用本地的全屏控制。默認(rèn)為NO
@property (nonatomic) BOOL allowsInlineMediaPlayback;
// 控制用戶與webview進(jìn)行選擇交互時的粒度,可以選擇整個塊兒,或單個符號.
@property (nonatomic) WKSelectionGranularity selectionGranularity;

3. WKUserContentController

WKUserContentController 是JavaScript與原生進(jìn)行交互的橋梁,主要方法:

// JS 端可通過 window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 發(fā)送消息
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
// 移除注入的協(xié)議, 在deinit方法中調(diào)用
- (void)removeScriptMessageHandlerForName:(NSString *)name;
// 通過WKUserScript注入需要執(zhí)行的JavaScript代碼
- (void)addUserScript:(WKUserScript *)userScript;
// 移除所有注入的JavaScript代碼
- (void)removeAllUserScripts;

可通過addScriptMessageHandler:name:方法注冊JS與Native交互名字,可通過addUserScript :注入需要執(zhí)行的JS代碼。

3.1 JavaScript調(diào)用Native

Native代碼:

#pragma mark - Native配置代碼
//創(chuàng)建網(wǎng)頁配置對象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//自定義的WKScriptMessageHandler 是為了解決內(nèi)存不釋放的問題
WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
//這個類主要用來做native與JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注冊一個name為jsToOcNoPrams的js方法 設(shè)置處理接收J(rèn)S方法的對象
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToNative"];
config.userContentController = wkUController;

#pragma mark - Native代理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
    //用message.body獲得JS傳出的參數(shù)體
    NSDictionary * parameter = message.body;
    //JS調(diào)用OC
    if([message.name isEqualToString:@"jsToNative"]){
        // do something
    }
}

JavaScript代碼:

window.webkit.messageHandlers.jsToNative.postMessage({"params":"我是參數(shù)"});

4. WKUserScript

在WebKit框架中,我們還可以預(yù)先添加JS方法,供其他人員調(diào)用。WKUserScript就是幫助我們完成JS注入的類,它能幫助我們在頁面填充前或js填充完成后調(diào)用。

//以下代碼適配文本大小
NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
// NSString *jSString = @"alert(\"WKUserScript注入js\");";
//用于進(jìn)行JavaScript注入
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[config.userContentController addUserScript:wkUScript];

5. WKUIDelegate

這個代理方法, 主要是用來處理使用系統(tǒng)的彈框來替換JS中的一些彈框的,比如: 警告框, 選擇框, 輸入框, 主要使用的是下面三個代理方法:

/**  對應(yīng)js的alert方法
 webView中彈出警告框時調(diào)用, 只能有一個按鈕

 @param webView webView
 @param message 提示信息
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 警告框消失的時候調(diào)用, 回調(diào)給JS
 */
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"警告" message:message preferredStyle:(UIAlertControllerStyleAlert)];
    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"我知道了" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    
    [alert addAction:ok];
    [self presentViewController:alert animated:YES completion:nil];
}

/** 對應(yīng)js的confirm方法
 webView中彈出選擇框時調(diào)用, 兩個按鈕

 @param webView webView description
 @param message 提示信息
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 確認(rèn)框消失的時候調(diào)用, 回調(diào)給JS, 參數(shù)為選擇結(jié)果: YES or NO
 */
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請選擇" message:message preferredStyle:(UIAlertControllerStyleAlert)];
    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"同意" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }];
    
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"不同意" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }];
    
    [alert addAction:ok];
    [alert addAction:cancel];
    [self presentViewController:alert animated:YES completion:nil];
}

/** 對應(yīng)js的prompt方法
 webView中彈出輸入框時調(diào)用, 兩個按鈕 和 一個輸入框

 @param webView webView description
 @param prompt 提示信息
 @param defaultText 默認(rèn)提示文本
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 輸入框消失的時候調(diào)用, 回調(diào)給JS, 參數(shù)為輸入的內(nèi)容
 */
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler {
    
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請輸入" message:prompt preferredStyle:(UIAlertControllerStyleAlert)];

    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"請輸入";
    }];
    
    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        
        UITextField *tf = [alert.textFields firstObject];
        
                completionHandler(tf.text);
    }];
    
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
                completionHandler(defaultText);
    }];
    
    [alert addAction:ok];
    [alert addAction:cancel];
    [self presentViewController:alert animated:YES completion:nil];
}

// 頁面是彈出窗口 _blank 處理
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

6. WKNavigationDelegate

主要處理一些跳轉(zhuǎn)、加載處理操作。

// main frame的導(dǎo)航開始請求時調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
   NSLog(@"開始加載");
}

// 當(dāng)main frame開始加載數(shù)據(jù)失敗時,會回調(diào)
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
  [self.progressView setProgress:0.0f animated:NO];
}

// 當(dāng)內(nèi)容開始返回時調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{  
}

//當(dāng)main frame導(dǎo)航完成時,會回調(diào)
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    // 頁面加載完成之后調(diào)用
}

// 當(dāng)main frame最后下載數(shù)據(jù)失敗時,會回調(diào)
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
  [self.progressView setProgress:0.0f animated:NO];
}

// 當(dāng)main frame接收到服務(wù)重定向時調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
    // 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用
}

// 根據(jù)WebView對于即將跳轉(zhuǎn)的HTTP請求頭信息和相關(guān)信息來決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
    NSString * urlStr = navigationAction.request.URL.absoluteString;
    NSLog(@"發(fā)送跳轉(zhuǎn)請求:%@",urlStr);
    //自己定義的協(xié)議頭
    NSString *htmlHeadString = @"github://";
    if([urlStr hasPrefix:htmlHeadString]){
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通過截取URL調(diào)用OC" message:@"你想前往我的Github主頁?" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            
        }])];
        [alertController addAction:([UIAlertAction actionWithTitle:@"打開" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];
            [[UIApplication sharedApplication] openURL:url];
            
        }])];
        [self presentViewController:alertController animated:YES completion:nil];
        
        decisionHandler(WKNavigationActionPolicyCancel);
        
    }else{
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}  

// 根據(jù)客戶端受到的服務(wù)器響應(yīng)頭以及response相關(guān)信息來決定是否可以跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    NSString * urlStr = navigationResponse.response.URL.absoluteString;
    NSLog(@"當(dāng)前跳轉(zhuǎn)地址:%@",urlStr);
    //允許跳轉(zhuǎn)
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不允許跳轉(zhuǎn)
    //decisionHandler(WKNavigationResponsePolicyCancel);
}

//用于授權(quán)驗(yàn)證的API,與AFN、UIWebView的授權(quán)驗(yàn)證API是一樣的
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler{
    //用戶身份信息
    NSURLCredential * newCred = [[NSURLCredential alloc] initWithUser:@"user123" password:@"123" persistence:NSURLCredentialPersistenceNone];
    //為 challenge 的發(fā)送方提供 credential
    [challenge.sender useCredential:newCred forAuthenticationChallenge:challenge];
    completionHandler(NSURLSessionAuthChallengeUseCredential,newCred);
}

// 當(dāng)web content處理完成時,會回調(diào)
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {

}

7. WKWebsiteDataStore

WKWebsiteDataStore 提供了網(wǎng)站所能使用的數(shù)據(jù)類型,包括 cookies,硬盤緩存,內(nèi)存緩存活在一些WebSQL的數(shù)據(jù)持久化和本地持久化。可通過 WKWebViewConfiguration 類的屬性 websiteDataStore 進(jìn)行相關(guān)的設(shè)置。

// 默認(rèn)的data store
+ (WKWebsiteDataStore *)defaultDataStore;

// 如果為webView設(shè)置了這個data Store,則不會有數(shù)據(jù)緩存被寫入文件
// 當(dāng)需要實(shí)現(xiàn)隱私瀏覽的時候,可使用這個
+ (WKWebsiteDataStore *)nonPersistentDataStore;

// 是否是可緩存數(shù)據(jù)的,只讀
@property (nonatomic, readonly, getter=isPersistent) BOOL persistent;

// 獲取所有可使用的數(shù)據(jù)類型
+ (NSSet<NSString *> *)allWebsiteDataTypes;

// 查找指定類型的緩存數(shù)據(jù)
// 回調(diào)的值是WKWebsiteDataRecord的集合
- (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler;

// 刪除指定的紀(jì)錄
// 這里的參數(shù)是通過上面的方法查找到的WKWebsiteDataRecord實(shí)例獲取的
- (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler;

// 刪除某時間后修改的某類型的數(shù)據(jù)
- (void)removeDataOfTypes:(NSSet<NSString *> *)websiteDataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler;

// 保存的HTTP cookies
@property (nonatomic, readonly) WKHTTPCookieStore *httpCookieStore

7.1 WebsiteDataTypes

// 硬盤緩存
WKWebsiteDataTypeDiskCache,
// HTML離線web應(yīng)用程序緩存
WKWebsiteDataTypeOfflineWebApplicationCache,
// 內(nèi)存緩存
WKWebsiteDataTypeMemoryCache,
// 本地緩存
WKWebsiteDataTypeLocalStorage,
// cookies
WKWebsiteDataTypeCookies,
// HTML會話存儲
WKWebsiteDataTypeSessionStorage,
//  IndexedDB 數(shù)據(jù)庫
WKWebsiteDataTypeIndexedDBDatabases,
// WebSQL 數(shù)據(jù)庫
WKWebsiteDataTypeWebSQLDatabases

7.2 WKHTTPCookieStore

用于管理WKWebView中的Cookie

/*!  查找所有已存儲的cookie
 */
- (void)getAllCookies:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler;

/*! 保存一個cookie, 保存成功后, 會走一次回調(diào)方法
 */
- (void)setCookie:(NSHTTPCookie *)cookie completionHandler:(nullable void (^)(void))completionHandler;

/*! 刪除一個cookie, 待刪除的cookie對象可通過 'getAllCookies' 方法獲取
 */
- (void)deleteCookie:(NSHTTPCookie *)cookie completionHandler:(nullable void (^)(void))completionHandler;

/*! 添加一個觀察者, 需要遵循協(xié)議 WKHTTPCookieStoreObserver 
當(dāng)cookie發(fā)送變化時, 會通過 WKHTTPCookieStoreObserver 的協(xié)議方法通知該觀察者, 在使用完后需要移除觀察者
 */
- (void)addObserver:(id<WKHTTPCookieStoreObserver>)observer;

/*! 移除觀察者
 */
- (void)removeObserver:(id<WKHTTPCookieStoreObserver>)observer;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容