參考文章:http://www.cocoachina.com/ios/20180831/24753.htmljavascript
WK時蘋果在iOS8.0以後推出的控件,相比於UIWebView:html
使用時,首先要添加頭文件:java
#import <WebKit/WebKit.h>ios
簡單建立一個WKWebView:web
self.iWKWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-64)]; //此處協議下面會講到 self.iWKWebView.navigationDelegate = self; self.iWKWebView.UIDelegate = self; self.iWKWebView.allowsBackForwardNavigationGestures = YES; NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.iWKWebView loadRequest:request]; [self.view addSubview:self.iWKWebView];
基本用法和UIWebView差很少。數據庫
這裏介紹幾個主要的類:macos
WKWebViewConfiguration緩存
WKPreferences服務器
WKUserContentControllercookie
WKWebsiteDataStore
1. WKWebView:
經常使用屬性:
// 導航代理 @property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate; // UI代理 @property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate; // 頁面標題, 通常使用KVO動態獲取 @property (nullable, nonatomic, readonly, copy) NSString *title; // 頁面加載進度, 通常使用KVO動態獲取 @property (nonatomic, readonly) double estimatedProgress; // 可返回的頁面列表, 已打開過的網頁, 有點相似於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, 因此若是想設置scrollView的一些屬性, 須要對此屬性進行配置 @property (nonatomic, readonly, strong) UIScrollView *scrollView; // 是否容許手勢左滑返回上一級, 相似導航控制的左滑返回 @property (nonatomic) BOOL allowsBackForwardNavigationGestures; //自定義UserAgent, 會覆蓋默認的值 ,iOS 9以後有效 @property (nullable, nonatomic, copy) NSString *customUserAgent
經常使用方法:
// 帶配置信息的初始化方法 // 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; // 前進下一級, 須要曾經打開過, 才能前進 - (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;
2. WKWebViewConfiguration:配置信息
能夠用配置信息來初始化WKWebView.
屬性有:
//關於網頁的設置 @property (nonatomic, strong) WKPreferences *preferences; //JavaScript與原生交互的橋樑 @property (nonatomic, strong) WKUserContentController *userContentController; //提供了網站所能使用的數據類型 @property (nonatomic, strong) WKWebsiteDataStore *websiteDataStore API_AVAILABLE(macosx(10.11), ios(9.0)); //是否容許播放媒體文件 @property (nonatomic) BOOL allowsAirPlayForMediaPlayback API_AVAILABLE(macosx(10.11), ios(9.0)); //是使用h5的視頻播放器在線播放, 仍是使用原生播放器全屏播放 @property (nonatomic) BOOL allowsInlineMediaPlayback; //須要用戶容許才能播放的媒體類型 @property (nonatomic) WKAudiovisualMediaTypes mediaTypesRequiringUserActionForPlayback API_AVAILABLE(macosx(10.12), ios(10.0));
2.1 WKPreference:
WKPreferences *preference = [[WKPreferences alloc]init]; //最小字體大小 preference.minimumFontSize = 0; //是否支持javaScript,默認YES preference.javaScriptEnabled = YES; //是否容許不通過用戶交互由javaScript自動打開窗口 preference.javaScriptCanOpenWindowsAutomatically = YES;
2.2 WKUserContentController
// 注入JavaScript與原生交互協議 // JS 端可經過 window.webkit.messageHandlers..postMessage() 發送消息 - (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name; // 移除注入的協議, 在deinit方法中調用 - (void)removeScriptMessageHandlerForName:(NSString *)name; // 經過WKUserScript注入須要執行的JavaScript代碼 - (void)addUserScript:(WKUserScript *)userScript; // 移除全部注入的JavaScript代碼 - (void)removeAllUserScripts;
使用WKUserContentController注入的交互協議, 須要遵循WKScriptMessageHandler協議, 在其協議方法中獲取JavaScript端傳遞的事件和參數:
JS調用OC:
簡單理解就是:[userController addScriptMessageHandler:self name:@"JSSendToOC"];//userController是一個WKUserContentController對象,‘JSSendToOC’是方法名,
當JS端經過window.webkit.messageHandlers.JSSendToOC.postMessage()方法調用'JSSendToOC'方法時,咱們能夠經過下面的協議方法獲取到JS端傳過來的數據,作咱們的操做。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message; WKScriptMessage包含了傳遞的協議名稱及參數, 主要從下面的屬性中獲取: // 協議名稱, 即上面的add方法傳遞的name @property (nonatomic, readonly, copy) NSString *name; // 傳遞的參數 @property (nonatomic, readonly, copy) id body;
OC調用JS:
NSString *js = @"callJsFunction('hahaha')"; [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) { NSLog(@"response:%@..error:%@",response,error); }];
這裏是調用了JS的‘callJsFunction’方法,這個方法名是隨便起的。
2.3 WKWebsiteDataStore
WKWebsiteDataStore 提供了網站所能使用的數據類型,包括 cookies,硬盤緩存,內存緩存活在一些WebSQL的數據持久化和本地持久化。可經過 WKWebViewConfiguration類的屬性 websiteDataStore 進行相關的設置。WKWebsiteDataStore相關的API也比較簡單:
// 默認的data store + (WKWebsiteDataStore *)defaultDataStore; // 若是爲webView設置了這個data Store,則不會有數據緩存被寫入文件 // 當須要實現隱私瀏覽的時候,可以使用這個 + (WKWebsiteDataStore *)nonPersistentDataStore; // 是不是可緩存數據的,只讀 @property (nonatomic, readonly, getter=isPersistent) BOOL persistent; // 獲取全部可以使用的數據類型 + (NSSet<NSString *> *)allWebsiteDataTypes; // 查找指定類型的緩存數據 // 回調的值是WKWebsiteDataRecord的集合 - (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler; // 刪除指定的紀錄 // 這裏的參數是經過上面的方法查找到的WKWebsiteDataRecord實例獲取的 - (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler; // 刪除某時間後修改的某類型的數據 - (void)removeDataOfTypes:(NSSet<NSString *> *)websiteDataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler; // 保存的HTTP cookies @property (nonatomic, readonly) WKHTTPCookieStore *httpCookieStore
dataTypes:
// 硬盤緩存 WKWebsiteDataTypeDiskCache, // HTML離線web應用程序緩存 WKWebsiteDataTypeOfflineWebApplicationCache, // 內存緩存 WKWebsiteDataTypeMemoryCache, // 本地緩存 WKWebsiteDataTypeLocalStorage, // cookies WKWebsiteDataTypeCookies, // HTML會話存儲 WKWebsiteDataTypeSessionStorage, // IndexedDB 數據庫 WKWebsiteDataTypeIndexedDBDatabases, // WebSQL 數據庫 WKWebsiteDataTypeWebSQLDatabases
dataRecord:
// 展現名稱, 一般是域名 @property (nonatomic, readonly, copy) NSString *displayName; // 包含的數據類型 @property (nonatomic, readonly, copy) NSSet<NSString *> *dataTypes;
關於此類的簡單使用:
1.刪除指定時間的全部類型數據
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes]; NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0]; [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{ // Done NSLog(@"釋放"); }];
2.查找刪除
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 }]; } }];
3.查找刪除特定的內容
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 }]; } } }];
WKNavigationDelegate:
#pragma mark - WKNavigationDelegate //請求加載以前,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ NSLog(@"加載前容許跳轉"); decisionHandler(WKNavigationActionPolicyAllow); } //開始加載時調用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{ NSLog(@"開始加載"); } //收到響應開始加載後,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ NSLog(@"收到響應後容許跳轉"); decisionHandler(WKNavigationResponsePolicyAllow); } //內容開始返回時調用 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{ NSLog(@"開始返回內容"); } //加載完成時調用 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{ NSLog(@"加載完成"); self.title = webView.title; } //加載失敗調用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{ NSLog(@"加載失敗"); } //收到服務器重定向請求後調用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{ NSLog(@"服務器重定向"); } //當main frame最後下載數據失敗時,會回調 - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{ NSLog(@"返回內容發生錯誤"); } //用於受權驗證的API,與AFN、UIWebView的受權驗證API是同樣的 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,nil); } //當web content處理完成時,會回調 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0)){ NSLog(@"WebContent完成"); }
這裏放一個完整的WKWebView例子,僅供參考:
//初始化WKPreferences,並設置相關屬性 WKPreferences *preference = [[WKPreferences alloc]init]; //初始化WKUserContentController,並設置相關屬性 WKUserContentController *userController = [[WKUserContentController alloc]init]; // 添加在js中操做的對象名稱,經過該對象來向web view發送消息 // JS 端可經過 window.webkit.messageHandlers..postMessage() 發送消息 // <script type="text/javascript"> // function clickBtn(){ // var dict = {"name":"tom","age":"20"}; // window.webkit.messageHandlers.JSSendToOC.postMessage(dict); // } // </script> [userController addScriptMessageHandler:self name:@"JSSendToOC"]; //初始化WKWebsiteDataStore,並設置相關屬性 WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore]; // 若是爲webView設置了這個data Store,則不會有數據緩存被寫入文件 // 當須要實現隱私瀏覽的時候,可以使用這個 // WKWebsiteDataStore *dataStore = [WKWebsiteDataStore nonPersistentDataStore]; //配置信息 WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init]; configuration.preferences = preference; configuration.userContentController = userController; configuration.websiteDataStore = dataStore; self.iWKWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-64) configuration:configuration]; self.iWKWebView.navigationDelegate = self; self.iWKWebView.UIDelegate = self; self.iWKWebView.allowsBackForwardNavigationGestures = YES; NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.iWKWebView loadRequest:request]; [self.view addSubview:self.iWKWebView];
再加一個知識點:WKWebView加載的時候添加一個自定義的進度條。
此時咱們須要獲取到webview加載的進度數值。
這裏能夠經過添加監聽來獲取。
[self.iWKWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
estimatedProgress是WKWebView的一個屬性。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ if ([keyPath isEqualToString:@"estimatedProgress"] && object==self.iWKWebView) { //獲取到webview的進度數值,加載自定義的進度條 //self.iWKWebView.estimatedProgress } }