iOS-WKWebView的使用

參考文章:http://www.cocoachina.com/ios/20180831/24753.htmljavascript

 

WK時蘋果在iOS8.0以後推出的控件,相比於UIWebView:html

  • 內存消耗少;
  • 解決了網頁加載時的內存泄漏問題;
  • 與HTML頁面的交互更方便;
  • 總之,其性能比UIWebView好不少。

使用時,首先要添加頭文件: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

  • WKWebView
  • 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完成");
}
View Code

 

這裏放一個完整的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
    }
    
}
相關文章
相關標籤/搜索