WKWebView是蘋果在iOS 8之后推出的框架WebKit中的瀏覽器控件, 其加載速度比UIWebView快了許多, 但內(nèi)存占用率卻下降很多, 也解決了加載網(wǎng)頁(yè)時(shí)的內(nèi)存泄露問(wèn)題. 現(xiàn)在的項(xiàng)目大多數(shù)只需適配到iOS 8, 所以用WKWebView來(lái)替換項(xiàng)目中的UIWebView是很有必要的.
WKWebView的使用主要涉及下面幾個(gè)類:
WKWebView
WKWebViewConfiguration
WKUserScript
WKUserContentController
WKWebsiteDataStore
以及兩個(gè)代理:
WKNavigationDelegate
WKUIDelegate
1. WKWebView
1.1 常用屬性
// 導(dǎo)航代理@property(nullable,nonatomic,weak)id navigationDelegate;// UI代理@property(nullable,nonatomic,weak)idUIDelegate;// 頁(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)doubleestimatedProgress;// 可返回的頁(yè)面列表, 已打開過(guò)的網(wǎng)頁(yè), 有點(diǎn)類似于navigationController的viewControllers屬性@property(nonatomic,readonly,strong)WKBackForwardList*backForwardList;// 頁(yè)面url@property(nullable,nonatomic,readonly,copy)NSURL*URL;// 頁(yè)面是否在加載中@property(nonatomic,readonly,getter=isLoading)BOOLloading;// 是否可返回@property(nonatomic,readonly)BOOLcanGoBack;// 是否可向前@property(nonatomic,readonly)BOOLcanGoForward;// WKWebView繼承自UIView, 所以如果想設(shè)置scrollView的一些屬性, 需要對(duì)此屬性進(jìn)行配置@property(nonatomic,readonly,strong)UIScrollView*scrollView;// 是否允許手勢(shì)左滑返回上一級(jí), 類似導(dǎo)航控制的左滑返回@property(nonatomic)BOOLallowsBackForwardNavigationGestures;//自定義UserAgent, 會(huì)覆蓋默認(rèn)的值 ,iOS 9之后有效@property(nullable,nonatomic,copy)NSString*customUserAgent
1.2 一些方法:
// 帶配置信息的初始化方法// configuration 配置信息- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration*)configuration// 加載請(qǐng)求- (nullableWKNavigation*)loadRequest:(NSURLRequest*)request;// 加載HTML- (nullableWKNavigation*)loadHTMLString:(NSString*)string baseURL:(nullableNSURL*)baseURL;// 返回上一級(jí)- (nullableWKNavigation*)goBack;// 前進(jìn)下一級(jí), 需要曾經(jīng)打開過(guò), 才能前進(jìn)- (nullableWKNavigation*)goForward;// 刷新頁(yè)面- (nullableWKNavigation*)reload;// 根據(jù)緩存有效期來(lái)刷新頁(yè)面- (nullableWKNavigation*)reloadFromOrigin;// 停止加載頁(yè)面- (void)stopLoading;// 執(zhí)行JavaScript代碼- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void(^ _Nullable)(_Nullableid,NSError* _Nullable error))completionHandler;
2. 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)打開新的窗口@property(nonatomic,strong)WKPreferences*preferences;// 是否允許播放媒體文件@property(nonatomic)BOOLallowsAirPlayForMediaPlayback// 需要用戶來(lái)操作才能播放的多媒體類型@property(nonatomic)WKAudiovisualMediaTypesmediaTypesRequiringUserActionForPlayback// 是使用h5的視頻播放器在線播放, 還是使用原生播放器全屏播放@property(nonatomic)BOOLallowsInlineMediaPlayback;
3. WKUserContentController
WKUserContentController 是JavaScript與原生進(jìn)行交互的橋梁, 主要使用的方法有:
// 注入JavaScript與原生交互協(xié)議// JS 端可通過(guò) window.webkit.messageHandlers..postMessage() 發(fā)送消息- (void)addScriptMessageHandler:(id)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é)議名稱及參數(shù), 主要從下面的屬性中獲取:
// 協(xié)議名稱, 即上面的add方法傳遞的name@property(nonatomic,readonly,copy)NSString*name;// 傳遞的參數(shù)@property(nonatomic,readonly,copy)idbody;
4. 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;
5. 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 = [UIAlertControlleralertControllerWithTitle:@"警告"message:message preferredStyle:(UIAlertControllerStyleAlert)];UIAlertAction*ok = [UIAlertActionactionWithTitle:@"我知道了"style:(UIAlertActionStyleDefault) handler:^(UIAlertAction* _Nonnull action) {? ? ? ? completionHandler();? ? }];? ? ? ? [alert addAction:ok];? ? [selfpresentViewController:alert animated:YEScompletion: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(^)(BOOLresult))completionHandler {UIAlertController*alert = [UIAlertControlleralertControllerWithTitle:@"請(qǐng)選擇"message:message preferredStyle:(UIAlertControllerStyleAlert)];UIAlertAction*ok = [UIAlertActionactionWithTitle:@"同意"style:(UIAlertActionStyleDefault) handler:^(UIAlertAction* _Nonnull action) {? ? ? ? completionHandler(YES);? ? }];UIAlertAction*cancel = [UIAlertActionactionWithTitle:@"不同意"style:(UIAlertActionStyleCancel) handler:^(UIAlertAction* _Nonnull action) {? ? ? ? completionHandler(NO);? ? }];? ? ? ? [alert addAction:ok];? ? [alert addAction:cancel];? ? [selfpresentViewController:alert animated:YEScompletion: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:(nullableNSString*)defaultText initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void(^)(NSString* _Nullable result))completionHandler {UIAlertController*alert = [UIAlertControlleralertControllerWithTitle:@"請(qǐng)輸入"message:prompt preferredStyle:(UIAlertControllerStyleAlert)];? ? ? ? [alert addTextFieldWithConfigurationHandler:^(UITextField* _Nonnull textField) {? ? ? ? textField.placeholder =@"請(qǐng)輸入";? ? }];UIAlertAction*ok = [UIAlertActionactionWithTitle:@"確定"style:(UIAlertActionStyleDefault) handler:^(UIAlertAction* _Nonnull action) {UITextField*tf = [alert.textFields firstObject];? ? ? ? ? ? ? ? ? ? ? ? completionHandler(tf.text);? ? }];UIAlertAction*cancel = [UIAlertActionactionWithTitle:@"取消"style:(UIAlertActionStyleCancel) handler:^(UIAlertAction* _Nonnull action) {? ? ? ? ? ? ? ? completionHandler(defaultText);? ? }];? ? ? ? [alert addAction:ok];? ? [alert addAction:cancel];? ? [selfpresentViewController:alert animated:YEScompletion:nil];}
6. 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(^)(NSURLSessionAuthChallengeDispositiondisposition,NSURLCredential*__nullablecredential))completionHandler{? ? ? ? completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,nil);}// main frame的導(dǎo)航開始請(qǐng)求時(shí)調(diào)用- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(null_unspecifiedWKNavigation*)navigation{? }// 當(dāng)main frame接收到服務(wù)重定向時(shí)調(diào)用- (void)webView:(WKWebView*)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecifiedWKNavigation*)navigation{// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用}// 當(dāng)main frame開始加載數(shù)據(jù)失敗時(shí)允蜈,會(huì)回調(diào)- (void)webView:(WKWebView*)webView didFailProvisionalNavigation:(null_unspecifiedWKNavigation*)navigation withError:(NSError*)error {}// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用- (void)webView:(WKWebView*)webView didCommitNavigation:(null_unspecifiedWKNavigation*)navigation{? }//當(dāng)main frame導(dǎo)航完成時(shí)冤吨,會(huì)回調(diào)- (void)webView:(WKWebView*)webView didFinishNavigation:(null_unspecifiedWKNavigation*)navigation{// 頁(yè)面加載完成之后調(diào)用}// 當(dāng)main frame最后下載數(shù)據(jù)失敗時(shí),會(huì)回調(diào)- (void)webView:(WKWebView*)webView didFailNavigation:(null_unspecifiedWKNavigation*)navigation withError:(NSError*)error {}// 當(dāng)web content處理完成時(shí)饶套,會(huì)回調(diào)- (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView {}
7. WKWebsiteDataStore
WKWebsiteDataStore提供了網(wǎng)站所能使用的數(shù)據(jù)類型漩蟆,包括 cookies,硬盤緩存妓蛮,內(nèi)存緩存活在一些WebSQL的數(shù)據(jù)持久化和本地持久化爆安。可通過(guò) ** WKWebViewConfiguration類的屬性 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ù)緩存被寫入文件// 當(dāng)需要實(shí)現(xiàn)隱私瀏覽的時(shí)候,可使用這個(gè)+ (WKWebsiteDataStore*)nonPersistentDataStore;// 是否是可緩存數(shù)據(jù)的咖耘,只讀@property(nonatomic,readonly,getter=isPersistent)BOOLpersistent;// 獲取所有可使用的數(shù)據(jù)類型+ (NSSet *)allWebsiteDataTypes;// 查找指定類型的緩存數(shù)據(jù)// 回調(diào)的值是WKWebsiteDataRecord的集合- (void)fetchDataRecordsOfTypes:(NSSet *)dataTypes completionHandler:(void(^)(NSArray *))completionHandler;// 刪除指定的紀(jì)錄// 這里的參數(shù)是通過(guò)上面的方法查找到的WKWebsiteDataRecord實(shí)例獲取的- (void)removeDataOfTypes:(NSSet *)dataTypes forDataRecords:(NSArray *)dataRecords completionHandler:(void(^)(void))completionHandler;// 刪除某時(shí)間后修改的某類型的數(shù)據(jù)- (void)removeDataOfTypes:(NSSet *)websiteDataTypes modifiedSince:(NSDate*)date completionHandler:(void(^)(void))completionHandler;// 保存的HTTP cookies@property(nonatomic,readonly)WKHTTPCookieStore*httpCookieStore
dataTyle
// 硬盤緩存WKWebsiteDataTypeDiskCache,// HTML離線web應(yīng)用程序緩存WKWebsiteDataTypeOfflineWebApplicationCache,// 內(nèi)存緩存WKWebsiteDataTypeMemoryCache,// 本地緩存WKWebsiteDataTypeLocalStorage,// cookiesWKWebsiteDataTypeCookies,// HTML會(huì)話存儲(chǔ)WKWebsiteDataTypeSessionStorage,//? IndexedDB 數(shù)據(jù)庫(kù)WKWebsiteDataTypeIndexedDBDatabases,// WebSQL 數(shù)據(jù)庫(kù)WKWebsiteDataTypeWebSQLDatabases
WKWebsiteDataRecord
// 展示名稱, 通常是域名@property(nonatomic,readonly,copy)NSString*displayName;// 包含的數(shù)據(jù)類型@property(nonatomic,readonly,copy)NSSet *dataTypes;
簡(jiǎn)單應(yīng)用
刪除指定時(shí)間的所有類型數(shù)據(jù)
NSSet*websiteDataTypes = [WKWebsiteDataStoreallWebsiteDataTypes];NSDate*dateFrom = [NSDatedateWithTimeIntervalSince1970:0];? ? [[WKWebsiteDataStoredefaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{// DoneNSLog(@"釋放");? ? }];
查找刪除
WKWebsiteDataStore*dataStore = [WKWebsiteDataStoredefaultDataStore];? ? [dataStore fetchDataRecordsOfTypes:[WKWebsiteDataStoreallWebsiteDataTypes] completionHandler:^(NSArray * _Nonnull records) {for(WKWebsiteDataRecord*recordinrecords) {? ? ? ? ? ? [dataStore removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{// done}];? ? ? ? }? ? }];
查找刪除特定的內(nèi)容
WKWebsiteDataStore*dataStore = [WKWebsiteDataStoredefaultDataStore];? ? [dataStore fetchDataRecordsOfTypes:[WKWebsiteDataStoreallWebsiteDataTypes] completionHandler:^(NSArray * _Nonnull records) {for(WKWebsiteDataRecord*recordinrecords) {if([record.displayName isEqualToString:@"baidu"]) {? ? ? ? ? ? ? ? [dataStore removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{// done}];? ? ? ? ? ? }? ? ? ? }? ? }];
來(lái)自:流火緋瞳? 鏈接:http://www.reibang.com/p/833448c30d70