前言:
目錄:
一罕扎、WKWebView基本介紹
二抵屿、WKWebView新特性
三庆锦、WebKit框架概覽
四、WKWebView的屬性
一晌该、WKWebView基本介紹
iOS8之前肥荔,應(yīng)用瀏覽網(wǎng)頁(yè)通常使用UIWebView這樣一個(gè)類(lèi)绿渣,由于這個(gè)類(lèi)加載速度慢、占用內(nèi)存大燕耿、還有內(nèi)存泄漏的問(wèn)題存在中符,通常需要開(kāi)發(fā)者自己優(yōu)化。
所以誉帅,在Apple WWDC 2014隨iOS8和OS X 10.10之后淀散,蘋(píng)果推出了新的網(wǎng)頁(yè)框架WebKit,優(yōu)化了UIWebView的內(nèi)存問(wèn)題蚜锨,功能非常的強(qiáng)大档插,WebKit中更新的WKWebView控件的新特性與使用方法,它很好的解決了UIWebView存在的內(nèi)存亚再、加載速度等諸多問(wèn)題郭膛。
二、WKWebView新特性
在性能氛悬、穩(wěn)定性则剃、功能方面有很大提升(最直觀(guān)的體現(xiàn)就是加載網(wǎng)頁(yè)是占用的內(nèi)存);
允許JavaScript的Nitro庫(kù)加載并使用(UIWebView中限制)如捅;
支持了更多的HTML5特性棍现;
高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢(shì);
將UIWebViewDelegate與UIWebView重構(gòu)成了14類(lèi)與3個(gè)協(xié)議查看蘋(píng)果官方文檔镜遣;
三己肮、WebKit框架概覽
WebKit框架概覽
如上圖所示,WebKit框架中最核心的類(lèi)應(yīng)該屬于WKWebView了悲关,這個(gè)類(lèi)專(zhuān)門(mén)用來(lái)渲染網(wǎng)頁(yè)視圖谎僻,其他類(lèi)和協(xié)議都將基于它和服務(wù)于它。
WKWebView:網(wǎng)頁(yè)的渲染與展示寓辱,通過(guò)WKWebViewConfiguration可以進(jìn)行自定義配置戈稿。
WKWebViewConfiguration:這個(gè)類(lèi)專(zhuān)門(mén)用來(lái)配置WKWebView。
WKPreference:這個(gè)類(lèi)用來(lái)進(jìn)行相關(guān)webView設(shè)置讶舰。
WKProcessPool:這個(gè)類(lèi)用來(lái)配置進(jìn)程池鞍盗,與網(wǎng)頁(yè)視圖的資源共享有關(guān)。
WKUserContentController:這個(gè)類(lèi)主要用來(lái)做native與JavaScript的交互管理跳昼。
WKUserScript:用于進(jìn)行JavaScript注入般甲。
WKScriptMessageHandler:這個(gè)類(lèi)專(zhuān)門(mén)用來(lái)處理JavaScript調(diào)用native的方法。
WKNavigationDelegate:這網(wǎng)頁(yè)跳轉(zhuǎn)間的導(dǎo)航管理協(xié)議鹅颊,這個(gè)協(xié)議可以監(jiān)聽(tīng)網(wǎng)頁(yè)的活動(dòng)敷存。
WKNavigationAction:網(wǎng)頁(yè)某個(gè)活動(dòng)的示例化對(duì)象。
WKUIDelegate:用于交互處理JavaScript中的一些彈出框。
WKBackForwardList:堆棧管理的網(wǎng)頁(yè)列表锚烦。
WKBackForwardListItem:每個(gè)網(wǎng)頁(yè)節(jié)點(diǎn)對(duì)象觅闽。
四、WKWebView的屬性
4.1 常用屬性
// 導(dǎo)航代理 @property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate; // UI代理 @property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate; // 頁(yè)面標(biāo)題, 一般使用KVO動(dòng)態(tài)獲取 @property (nullable, nonatomic, readonly, copy) NSString *title; // 頁(yè)面加載進(jìn)度, 一般使用KVO動(dòng)態(tài)獲取 @property (nonatomic, readonly) double estimatedProgress; // 可返回的頁(yè)面列表, 已打開(kāi)過(guò)的網(wǎng)頁(yè), 有點(diǎn)類(lèi)似于navigationController的viewControllers屬性 @property (nonatomic, readonly, strong) WKBackForwardList *backForwardList; // 頁(yè)面url @property (nullable, nonatomic, readonly, copy) NSURL *URL; // 頁(yè)面是否在加載中 @property (nonatomic, readonly, getter=isLoading) BOOL loading; // 是否可返回 @property (nonatomic, readonly) BOOL canGoBack; // 是否可向前 @property (nonatomic, readonly) BOOL canGoForward; // WKWebView繼承自UIView, 所以如果想設(shè)置scrollView的一些屬性, 需要對(duì)此屬性進(jìn)行配置 @property (nonatomic, readonly, strong) UIScrollView *scrollView; // 是否允許手勢(shì)左滑返回上一級(jí), 類(lèi)似導(dǎo)航控制的左滑返回 @property (nonatomic) BOOL allowsBackForwardNavigationGestures; /// 在iOS上默認(rèn)為NO涮俄,標(biāo)識(shí)不允許鏈接預(yù)覽 @property (nonatomic) BOOL allowsLinkPreview API_AVAILABLE(macosx(10.11), ios(9.0)); /// 網(wǎng)頁(yè)鏈接是否安全 @property (nonatomic, readonly) BOOL hasOnlySecureContent; /// 證書(shū)服務(wù) @property (nonatomic, readonly, nullable) SecTrustRef serverTrust API_AVAILABLE(macosx(10.12), ios(10.0)); //自定義UserAgent, 會(huì)覆蓋默認(rèn)的值 ,iOS 9之后有效 @property (nullable, nonatomic, copy) NSString *customUserAgent; /// 是否支持放大手勢(shì)蛉拙,默認(rèn)為NO @property (nonatomic) BOOL allowsMagnification; /// 放大因子,默認(rèn)為1 @property (nonatomic) CGFloat magnification; /// 據(jù)設(shè)置的縮放因子來(lái)縮放頁(yè)面彻亲,并居中顯示結(jié)果在指定的點(diǎn) - (void)setMagnification:(CGFloat)magnification centeredAtPoint:(CGPoint)point; /// 證書(shū)列表 @property (nonatomic, readonly, copy) NSArray *certificateChain API_DEPRECATED_WITH_REPLACEMENT("serverTrust", macosx(10.11, 10.12), ios(9.0, 10.0));
4.2 一些方法
// 帶配置信息的初始化方法 // configuration 配置信息 - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration // 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數(shù)據(jù)加載webView視圖 - (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0)); /// 返回上一個(gè)網(wǎng)頁(yè)節(jié)點(diǎn) - (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item; // 返回上一級(jí) - (nullable WKNavigation *)goBack; // 前進(jìn)下一級(jí), 需要曾經(jīng)打開(kāi)過(guò), 才能前進(jìn) - (nullable WKNavigation *)goForward; // 刷新頁(yè)面 - (nullable WKNavigation *)reload; // 根據(jù)緩存有效期來(lái)刷新頁(yè)面 - (nullable WKNavigation *)reloadFromOrigin; // 停止加載頁(yè)面 - (void)stopLoading; // 執(zhí)行JavaScript代碼 - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
4.3 WKWebViewConfiguration
// 通過(guò)此屬性來(lái)執(zhí)行JavaScript代碼來(lái)修改頁(yè)面的行為 @property (nonatomic, strong) WKUserContentController *userContentController; //***********下面屬性一般不需要設(shè)置 // 首選項(xiàng)設(shè)置, //可設(shè)置最小字號(hào), 是否允許執(zhí)行js //是否通過(guò)js自動(dòng)打開(kāi)新的窗口 @property (nonatomic, strong) WKPreferences *preferences; // 是否允許播放媒體文件 @property (nonatomic) BOOL allowsAirPlayForMediaPlayback // 需要用戶(hù)來(lái)操作才能播放的多媒體類(lèi)型 @property (nonatomic) WKAudiovisualMediaTypes mediaTypesRequiringUserActionForPlayback // 是使用h5的視頻播放器在線(xiàn)播放, 還是使用原生播放器全屏播放 @property (nonatomic) BOOL allowsInlineMediaPlayback;
4.4 WKUserContentController
WKUserContentController 是JavaScript與原生進(jìn)行交互的橋梁, 主要使用的方法有:// 注入JavaScript與原生交互協(xié)議 // JS 端可通過(guò) window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 發(fā)送消息 - (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name; // 移除注入的協(xié)議, 在deinit方法中調(diào)用 - (void)removeScriptMessageHandlerForName:(NSString *)name; // 通過(guò)WKUserScript注入需要執(zhí)行的JavaScript代碼 - (void)addUserScript:(WKUserScript *)userScript; // 移除所有注入的JavaScript代碼 - (void)removeAllUserScripts;
使用WKUserContentController注入的交互協(xié)議, 需要遵循WKScriptMessageHandler協(xié)議, 在其協(xié)議方法中獲取JavaScript端傳遞的事件和參數(shù):
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
WKScriptMessage包含了傳遞的協(xié)議名稱(chēng)及參數(shù), 主要從下面的屬性中獲取:
// 協(xié)議名稱(chēng), 即上面的add方法傳遞的name @property (nonatomic, readonly, copy) NSString *name; // 傳遞的參數(shù) @property (nonatomic, readonly, copy) id body;
4.5 WKUserScript
WKUserScript用于往加載的頁(yè)面中添加額外需要執(zhí)行的JavaScript代碼, 主要是一個(gè)初始化方法:/* source: 需要執(zhí)行的JavaScript代碼 injectionTime: 加入的位置, 是一個(gè)枚舉 typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) { WKUserScriptInjectionTimeAtDocumentStart, WKUserScriptInjectionTimeAtDocumentEnd } API_AVAILABLE(macosx(10.10), ios(8.0)); forMainFrameOnly: 是加入所有框架, 還是只加入主框架 */ - (instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;
4.6 WKUIDelegate
這個(gè)代理方法, 主要是用來(lái)處理使用系統(tǒng)的彈框來(lái)替換JS中的一些彈框的,比如: 警告框, 選擇框, 輸入框, 主要使用的是下面三個(gè)代理方法:/** webView中彈出警告框時(shí)調(diào)用, 只能有一個(gè)按鈕 @param webView webView @param message 提示信息 @param frame 可用于區(qū)分哪個(gè)窗口調(diào)用的 @param completionHandler 警告框消失的時(shí)候調(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]; }
.
/** 對(duì)應(yīng)js的confirm方法 webView中彈出選擇框時(shí)調(diào)用, 兩個(gè)按鈕 @param webView webView description @param message 提示信息 @param frame 可用于區(qū)分哪個(gè)窗口調(diào)用的 @param completionHandler 確認(rèn)框消失的時(shí)候調(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:@"請(qǐng)選擇" 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]; }
.
/** 對(duì)應(yīng)js的prompt方法 webView中彈出輸入框時(shí)調(diào)用, 兩個(gè)按鈕 和 一個(gè)輸入框 @param webView webView description @param prompt 提示信息 @param defaultText 默認(rèn)提示文本 @param frame 可用于區(qū)分哪個(gè)窗口調(diào)用的 @param completionHandler 輸入框消失的時(shí)候調(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:@"請(qǐng)輸入" message:prompt preferredStyle:(UIAlertControllerStyleAlert)]; [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { textField.placeholder = @"請(qǐng)輸入"; }]; 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]; }
4.7 WKNavigationDelegate
// 決定導(dǎo)航的動(dòng)作孕锄,通常用于處理跨域的鏈接能否導(dǎo)航。 // WebKit對(duì)跨域進(jìn)行了安全檢查限制苞尝,不允許跨域畸肆,因此我們要對(duì)不能跨域的鏈接單獨(dú)處理。 // 但是宙址,對(duì)于Safari是允許跨域的轴脐,不用這么處理。 // 這個(gè)是決定是否Request - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ // 在發(fā)送請(qǐng)求之前抡砂,決定是否跳轉(zhuǎn) decisionHandler(WKNavigationActionPolicyAllow); }
.
// 是否接收響應(yīng) - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ // 在收到響應(yīng)后豁辉,決定是否跳轉(zhuǎn)和發(fā)送請(qǐng)求之前那個(gè)允許配套使用 decisionHandler(WKNavigationResponsePolicyAllow); }
.
//用于授權(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{ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling ,nil); }
.
// main frame的導(dǎo)航開(kāi)始請(qǐng)求時(shí)調(diào)用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{ }
.
// 當(dāng)main frame接收到服務(wù)重定向時(shí)調(diào)用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{ // 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用 }
.
// 當(dāng)main frame開(kāi)始加載數(shù)據(jù)失敗時(shí),會(huì)回調(diào) - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { }
.
// 當(dāng)內(nèi)容開(kāi)始返回時(shí)調(diào)用 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{ }
.
//當(dāng)main frame導(dǎo)航完成時(shí)气破,會(huì)回調(diào) - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{ // 頁(yè)面加載完成之后調(diào)用 }
.
// 當(dāng)main frame最后下載數(shù)據(jù)失敗時(shí)聊浅,會(huì)回調(diào) - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error > { }
.
// 當(dāng)web content處理完成時(shí),會(huì)回調(diào) - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { }
4.8 WKWebsiteDataStore
WKWebsiteDataStore 提供了網(wǎng)站所能使用的數(shù)據(jù)類(lèi)型现使,包括 cookies低匙,硬盤(pán)緩存,內(nèi)存緩存活在一些WebSQL的數(shù)據(jù)持久化和本地持久化碳锈⊥缫保可通過(guò) ** WKWebViewConfiguration類(lèi)的屬性 websiteDataStore 進(jìn)行相關(guān)的設(shè)置。WKWebsiteDataStore** 相關(guān)的API也比較簡(jiǎn)單:// 默認(rèn)的data store + (WKWebsiteDataStore *)defaultDataStore; // 如果為webView設(shè)置了這個(gè)data Store售碳,則不會(huì)有數(shù)據(jù)緩存被寫(xiě)入文件 // 當(dāng)需要實(shí)現(xiàn)隱私瀏覽的時(shí)候强重,可使用這個(gè) + (WKWebsiteDataStore *)nonPersistentDataStore; // 是否是可緩存數(shù)據(jù)的,只讀 @property (nonatomic, readonly, getter=isPersistent) BOOL persistent; // 獲取所有可使用的數(shù)據(jù)類(lèi)型 + (NSSet<NSString *> *)allWebsiteDataTypes; // 查找指定類(lèi)型的緩存數(shù)據(jù) // 回調(diào)的值是WKWebsiteDataRecord的集合 - (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler; // 刪除指定的紀(jì)錄 // 這里的參數(shù)是通過(guò)上面的方法查找到的WKWebsiteDataRecord實(shí)例獲取的 - (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler; // 刪除某時(shí)間后修改的某類(lèi)型的數(shù)據(jù) - (void)removeDataOfTypes:(NSSet<NSString *> *)websiteDataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler; // 保存的HTTP cookies @property (nonatomic, readonly) WKHTTPCookieStore *httpCookieStore
dataTyle
// 硬盤(pán)緩存 WKWebsiteDataTypeDiskCache, // HTML離線(xiàn)web應(yīng)用程序緩存 WKWebsiteDataTypeOfflineWebApplicationCache, // 內(nèi)存緩存 WKWebsiteDataTypeMemoryCache, // 本地緩存 WKWebsiteDataTypeLocalStorage, // cookies WKWebsiteDataTypeCookies, // HTML會(huì)話(huà)存儲(chǔ) WKWebsiteDataTypeSessionStorage, // IndexedDB 數(shù)據(jù)庫(kù) WKWebsiteDataTypeIndexedDBDatabases, // WebSQL 數(shù)據(jù)庫(kù) WKWebsiteDataTypeWebSQLDatabases
WKWebsiteDataRecord
// 展示名稱(chēng), 通常是域名 @property (nonatomic, readonly, copy) NSString *displayName; // 包含的數(shù)據(jù)類(lèi)型 @property (nonatomic, readonly, copy) NSSet<NSString *> *dataTypes;
簡(jiǎn)單應(yīng)用
刪除指定時(shí)間的所有類(lèi)型數(shù)據(jù)WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore]; [dataStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] >completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) { for (WKWebsiteDataRecord *record in records) { [dataStore removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{ // done }]; } }];
查找刪除特定的內(nèi)容
WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore]; [dataStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] >completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) { for (WKWebsiteDataRecord *record in records) { if ([record.displayName isEqualToString:@"baidu"]) { [dataStore removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{ // done }]; } } }];
學(xué)習(xí)網(wǎng)站: