WKWebView學(xué)習(xí)筆記

一肌似、簡(jiǎn)介

webView是我們?nèi)粘i_發(fā)中不可缺少的一個(gè)組件,通常我們都是使用UIWebView來實(shí)現(xiàn)的,不過大多數(shù)情況下油航,UIWebView的表現(xiàn)卻不盡如人意(最直觀的就是內(nèi)存消耗嚴(yán)重蔑水,特別是有視頻的時(shí)候邢锯,有木有!)
iOS8之后蘋果推薦使用WKWebView替代UIWebView搀别,其主要的有點(diǎn)有:

  1. 在性能丹擎、穩(wěn)定性
  2. WKWebView更多的支持HTML5的特性
  3. WKWebView更快,占用內(nèi)存可能只有UIWebView的1/3 ~ 1/4
  4. WKWebView高達(dá)60fps的滾動(dòng)刷新率和豐富的內(nèi)置手勢(shì)
  5. WKWebView具有Safari相同的JavaScript引擎
  6. WKWebView增加了加載進(jìn)度屬性
  7. 將UIWebViewDelegate和UIWebView重構(gòu)成了14個(gè)類與3個(gè)協(xié)議官方鏈接

Classes:

  • WKBackForwardList: 之前訪問過的 web 頁面的列表歇父,可以通過后退和前進(jìn)動(dòng)作來訪問到蒂培。
  • WKBackForwardListItem: webview 中后退列表里的某一個(gè)網(wǎng)頁。
  • WKFrameInfo: 包含一個(gè)網(wǎng)頁的布局信息榜苫。
  • WKNavigation: 包含一個(gè)網(wǎng)頁的加載進(jìn)度信息护戳。
  • WKNavigationAction: 包含可能讓網(wǎng)頁導(dǎo)航變化的信息,用于判斷是否做出導(dǎo)航變化垂睬。
  • WKNavigationResponse: 包含可能讓網(wǎng)頁導(dǎo)航變化的返回內(nèi)容信息媳荒,用于判斷是否做出導(dǎo)航變化。
  • WKPreferences: 概括一個(gè) webview 的偏好設(shè)置驹饺。
  • WKProcessPool: 表示一個(gè) web 內(nèi)容加載池钳枕。
  • WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法。
  • WKScriptMessage: 包含網(wǎng)頁發(fā)出的信息赏壹。
  • WKUserScript: 表示可以被網(wǎng)頁接受的用戶腳本鱼炒。
  • WKWebViewConfiguration: 初始化 webview 的設(shè)置。
  • WKWindowFeatures: 指定加載新網(wǎng)頁時(shí)的窗口屬性蝌借。

Protocols

  • WKNavigationDelegate: 提供了追蹤主窗口網(wǎng)頁加載過程和判斷主窗口和子窗口是否進(jìn)行頁面加載新頁面的相關(guān)方法昔瞧。
  • WKScriptMessageHandler: 提供從網(wǎng)頁中收消息的回調(diào)方法。
  • WKUIDelegate: 提供用原生控件顯示網(wǎng)頁的方法回調(diào)菩佑。

廢話了這么多自晰,用一個(gè)剛剛測(cè)試過的圖來展示下內(nèi)存優(yōu)化了

WKWebView加載視頻.png

UIWebView加載視頻.png

差距了幾倍的內(nèi)存。下面就聊聊WKWebView的使用擎鸠。

二缀磕、簡(jiǎn)單使用

1.首先自然是導(dǎo)入頭文件(iOS9之后默認(rèn)不支持HTTP協(xié)議,別忘了在Info.plist里面添加支持)

#import<WebKit/WebKit.h>

2.初始化


(1)由于WKWebView的父類是UIView,所以可以用我們最常用的方法來初始化:

WKWebView *webView = [[WKWebView alloc]initWithFrame:self.view.frame];

(2)WKWebView自己也具備一個(gè)自己的初始化方法

- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration*)configuration

這里面WKWebViewConfiguration就是一個(gè)上面講述的重構(gòu)了類中的一個(gè)袜蚕,負(fù)責(zé)的內(nèi)容是:

A WKWebViewConfiguration object is a collection of properties used to initialize a web view.
WKWebViewConfiguration 是一個(gè)屬性的集合 用來初始化web視圖糟把。

這個(gè)類包含眾多的屬性,預(yù)知詳情請(qǐng)見官方文檔牲剃,這里介紹幾個(gè)常用的屬性(偏好的設(shè)置):

//初始化一個(gè)WKWebViewConfiguration對(duì)象
    WKWebViewConfiguration *config = [WKWebViewConfiguration new];
    //初始化偏好設(shè)置屬性:preferences
    config.preferences = [WKPreferences new];
    //The minimum font size in points default is 0;
    config.preferences.minimumFontSize = 10;
    //是否支持JavaScript
    config.preferences.javaScriptEnabled = YES;
    //不通過用戶交互遣疯,是否可以打開窗口
    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
    
    WKWebView *webView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:config];
    
    [self.view addSubview:webView];

3.加載網(wǎng)頁

最基礎(chǔ)的方法和UIWebView一樣

NSURL *url = [NSURL URLWithString:@"www.reibang.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

這里有幾個(gè)加載的方法:

//加載本地URL文件
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL 
               allowingReadAccessToURL:(NSURL *)readAccessURL

//加載本地HTML字符串
- (nullable WKNavigation *)loadHTMLString:(NSString *)string
                                  baseURL:(nullable NSURL *)baseURL;
//加載二進(jìn)制數(shù)據(jù)
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL

每個(gè)方法都會(huì)返回一個(gè)WKNavigation對(duì)象,官方介紹是

一個(gè)WKNavigation對(duì)象包含信息跟蹤加載一個(gè)網(wǎng)頁的進(jìn)展凿傅。
A WKNavigation object contains information for tracking the loading progress of a webpage.

導(dǎo)航web視圖加載方法返回的對(duì)象,也是傳遞到導(dǎo)航委托方法來唯一地標(biāo)識(shí)一個(gè)網(wǎng)頁加載從開始到結(jié)束缠犀。它沒有自己的方法或?qū)傩浴?br> A navigation object is returned from the web view load methods and is also passed to the navigation delegate methods to uniquely identify a webpage load from start to finish. It has no method or properties of its own.

然后我創(chuàng)建了兩個(gè)WKWebView,加載同樣的url聪舒,打印的結(jié)果是不同的地址:


這個(gè)屬性在WKWebView的代理方法里面有用到辨液,我的理解就是用來標(biāo)記不同的webView的。

三箱残、所有相關(guān)的類的API

這里的東西比較多滔迈,想看一些高級(jí)使用的直接跳過看下一節(jié),或者直接下載Demo

1.WKWebView

//上文介紹過的偏好配置
@property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
// 導(dǎo)航代理 
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
// 用戶交互代理
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
 
// 頁面前進(jìn)被辑、后退列表
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
 
// 默認(rèn)構(gòu)造器
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
 

//加載請(qǐng)求API
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
 
// 加載URL
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
 
// 直接加載HTML
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
 
// 直接加載data
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL NS_AVAILABLE(10_11, 9_0);
 
// 前進(jìn)或者后退到某一頁面
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
 
// 頁面的標(biāo)題燎悍,支持KVO的
@property (nullable, nonatomic, readonly, copy) NSString *title;
 
// 當(dāng)前請(qǐng)求的URL,支持KVO的
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
 
// 標(biāo)識(shí)當(dāng)前是否正在加載內(nèi)容中盼理,支持KVO的
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
 
// 當(dāng)前加載的進(jìn)度谈山,范圍為[0, 1]
@property (nonatomic, readonly) double estimatedProgress;
 
// 標(biāo)識(shí)頁面中的所有資源是否通過安全加密連接來加載,支持KVO的
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
 
// 當(dāng)前導(dǎo)航的證書鏈宏怔,支持KVO
@property (nonatomic, readonly, copy) NSArray *certificateChain NS_AVAILABLE(10_11, 9_0);
 
// 是否可以招待goback操作奏路,它是支持KVO的
@property (nonatomic, readonly) BOOL canGoBack;
 
// 是否可以執(zhí)行g(shù)ofarward操作,支持KVO
@property (nonatomic, readonly) BOOL canGoForward;
 
// 返回上一頁面臊诊,如果不能返回思劳,則什么也不干
- (nullable WKNavigation *)goBack;
 
// 進(jìn)入下一頁面,如果不能前進(jìn)妨猩,則什么也不干
- (nullable WKNavigation *)goForward;
 
// 重新載入頁面
- (nullable WKNavigation *)reload;
 
// 重新從原始URL載入
- (nullable WKNavigation *)reloadFromOrigin;
 
// 停止加載數(shù)據(jù)
- (void)stopLoading;
 
// 執(zhí)行JS代碼
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;
 
// 標(biāo)識(shí)是否支持左、右swipe手勢(shì)是否可以前進(jìn)秽褒、后退
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
 
// 自定義user agent壶硅,如果沒有則為nil
@property (nullable, nonatomic, copy) NSString *customUserAgent NS_AVAILABLE(10_11, 9_0);
 
// 在iOS上默認(rèn)為NO,標(biāo)識(shí)不允許鏈接預(yù)覽
@property (nonatomic) BOOL allowsLinkPreview NS_AVAILABLE(10_11, 9_0);
 
#if TARGET_OS_IPHONE
/*! @abstract The scroll view associated with the web view.
 */
@property (nonatomic, readonly, strong) UIScrollView *scrollView;
#endif
 
#if !TARGET_OS_IPHONE
// 標(biāo)識(shí)是否支持放大手勢(shì)销斟,默認(rèn)為NO
@property (nonatomic) BOOL allowsMagnification;
 
// 放大因子庐椒,默認(rèn)為1
@property (nonatomic) CGFloat magnification;
 
// 根據(jù)設(shè)置的縮放因子來縮放頁面,并居中顯示結(jié)果在指定的點(diǎn)
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(CGPoint)point;
 
#endif

2. WKPreferences偏好設(shè)置

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 設(shè)置偏好設(shè)置
config.preferences = [[WKPreferences alloc] init];
// 默認(rèn)為0
config.preferences.minimumFontSize = 10;
// 默認(rèn)認(rèn)為YES
config.preferences.javaScriptEnabled = YES;
// 在iOS上默認(rèn)為NO蚂踊,表示不能自動(dòng)通過窗口打開
config.preferences.javaScriptCanOpenWindowsAutomatically = NO;

3.WKProcessPool內(nèi)容處理池

這個(gè)類沒有公開的方法和屬性约谈,而且也并不需要配置,可以暫時(shí)忽略。

4. WKUserContentController內(nèi)容交互控制器

我們要通過JS與webview內(nèi)容交互棱诱,就需要到這個(gè)類了泼橘,它的所有屬性及方法說明如下:

// 只讀屬性,所有添加的WKUserScript都在這里可以獲取到
@property (nonatomic, readonly, copy) NSArray<WKUserScript *> *userScripts;
 
// 注入JS
- (void)addUserScript:(WKUserScript *)userScript;
 
// 移除所有注入的JS
- (void)removeAllUserScripts;
 
// 添加scriptMessageHandler到所有的frames中迈勋,則都可以通過
// window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
// 發(fā)送消息
// 比如炬灭,JS要調(diào)用我們?cè)姆椒ǎ涂梢酝ㄟ^這種方式了
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
 
// 根據(jù)name移除所注入的scriptMessageHandler
- (void)removeScriptMessageHandlerForName:(NSString *)name;

5. WKUserScript

在WKUserContentController中靡菇,所有使用到WKUserScript重归。WKUserContentController是用于與JS交互的類,而所注入的JS是WKUserScript對(duì)象厦凤。它的所有屬性和方法如下:

// JS源代碼
@property (nonatomic, readonly, copy) NSString *source;
 
// JS注入時(shí)間
@property (nonatomic, readonly) WKUserScriptInjectionTime injectionTime;
 
// 只讀屬性鼻吮,表示JS是否應(yīng)該注入到所有的frames中還是只有main frame.
@property (nonatomic, readonly, getter=isForMainFrameOnly) BOOL forMainFrameOnly;
 
// 初始化方法,用于創(chuàng)建WKUserScript對(duì)象
// source:JS源代碼
// injectionTime:JS注入的時(shí)間
// forMainFrameOnly:是否只注入main frame
- (instancetype)initWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)forMainFrameOnly;
 

6.WKWebsiteDataStore存儲(chǔ)的Web內(nèi)容

iOS9.0以后才能使用這個(gè)類较鼓。是代表webView不同的數(shù)據(jù)類型椎木,cookies、disk笨腥、memory caches拓哺、WebSQL、IndexedDB數(shù)據(jù)庫和本地存儲(chǔ)脖母。版本適配的化就要放棄了士鸥。

// 默認(rèn)數(shù)據(jù)存儲(chǔ)
+ (WKWebsiteDataStore *)defaultDataStore;
 
// 返回非持久化存儲(chǔ),數(shù)據(jù)不會(huì)寫入文件系統(tǒng)
+ (WKWebsiteDataStore *)nonPersistentDataStore;
 
// 只讀屬性谆级,表示是否是持久化存儲(chǔ)
@property (nonatomic, readonly, getter=isPersistent) BOOL persistent;
 
// 獲取所有web內(nèi)容的數(shù)據(jù)存儲(chǔ)類型集烤礁,比如cookies、disk等
+ (NSSet<NSString *> *)allWebsiteDataTypes;
 
// 獲取某些指定數(shù)據(jù)存儲(chǔ)類型的數(shù)據(jù)
- (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler;
 
// 刪除某些指定類型的數(shù)據(jù)
- (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;
 

7. WKWebsiteDataRecord

同樣iOS9.0之后可以使用肥照,website的數(shù)據(jù)存儲(chǔ)記錄類型脚仔,它只有兩個(gè)屬性:

// 通常是域名
@property (nonatomic, readonly, copy) NSString *displayName;
 
// 存儲(chǔ)的數(shù)據(jù)類型集
@property (nonatomic, readonly, copy) NSSet<NSString *> *dataTypes;

8. WKNavigationDelegate

@protocol WKNavigationDelegate <NSObject>
 
@optional
 
// 決定導(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;
 
// 決定是否接收響應(yīng)
// 這個(gè)是決定是否接收response
// 要獲取response硫嘶,通過WKNavigationResponse對(duì)象獲取
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
 
// 當(dāng)main frame的導(dǎo)航開始請(qǐng)求時(shí),會(huì)調(diào)用此方法
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
 
// 當(dāng)main frame接收到服務(wù)重定向時(shí)梧税,會(huì)回調(diào)此方法
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
 
// 當(dāng)main frame開始加載數(shù)據(jù)失敗時(shí)沦疾,會(huì)回調(diào)
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
 
// 當(dāng)main frame的web內(nèi)容開始到達(dá)時(shí)称近,會(huì)回調(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;
 
// 當(dāng)main frame最后下載數(shù)據(jù)失敗時(shí)哮塞,會(huì)回調(diào)
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
 
// 這與用于授權(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;
 
// 當(dāng)web content處理完成時(shí)彻桃,會(huì)回調(diào)
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
 
@end
 

9. WKNavigationResponse

WKNavigationResponse是導(dǎo)航響應(yīng)類坛善,通過它可以獲取相關(guān)響應(yīng)的信息:

NS_CLASS_AVAILABLE(10_10, 8_0)
@interface WKNavigationResponse : NSObject
 
// 是否是main frame
@property (nonatomic, readonly, getter=isForMainFrame) BOOL forMainFrame;
 
// 獲取響應(yīng)response
@property (nonatomic, readonly, copy) NSURLResponse *response;
 
// 是否顯示MIMEType
@property (nonatomic, readonly) BOOL canShowMIMEType;
 
@end

10. WKNavigationAction

WKNavigationAction對(duì)象包含關(guān)于導(dǎo)航的action的信息,用于make policy decisions邻眷。它只有以下幾個(gè)屬性:

// 正在請(qǐng)求的導(dǎo)航的frame
@property (nonatomic, readonly, copy) WKFrameInfo *sourceFrame;
// 目標(biāo)frame眠屎,如果這是新的window,它會(huì)是nil
@property (nullable, nonatomic, readonly, copy) WKFrameInfo *targetFrame; 
// 導(dǎo)航類型肆饶,如下面的小標(biāo)題WKNavigationType
@property (nonatomic, readonly) WKNavigationType navigationType;
// 導(dǎo)航的請(qǐng)求
@property (nonatomic, readonly, copy) NSURLRequest *request;

11. WKUIDelegate

@protocol WKUIDelegate <NSObject>
 
@optional
 
// 創(chuàng)建新的webview
// 可以指定配置對(duì)象改衩、導(dǎo)航動(dòng)作對(duì)象、window特性
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
 
// webview關(guān)閉時(shí)回調(diào)
- (void)webViewDidClose:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
 
// 調(diào)用JS的alert()方法
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
 
// 調(diào)用JS的confirm()方法
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
 
// 調(diào)用JS的prompt()方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
 
@end

12. WKBackForwardList

WKBackForwardList表示webview中可以前進(jìn)或者后退的頁面列表驯镊。其聲明如下:

NS_CLASS_AVAILABLE(10_10, 8_0)
@interface WKBackForwardList : NSObject
 
// 當(dāng)前正在顯示的item(頁面)
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *currentItem;
 
// 后一頁葫督,如果沒有就是nil
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *backItem;
 
// 前一頁,如果沒有就是nil
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *forwardItem;
 
// 根據(jù)下標(biāo)獲取某一個(gè)頁面的item
- (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index;
 
// 可以進(jìn)行g(shù)oback操作的頁面列表
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *backList;
 
// 可以進(jìn)行g(shù)oforward操作的頁面列表
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *forwardList;
 
@end

13. WKBackForwardListItem

頁面導(dǎo)航前進(jìn)板惑、后退列表項(xiàng):

NS_CLASS_AVAILABLE(10_10, 8_0)
@interface WKBackForwardListItem : NSObject
 
// 該頁面的URL
@property (readonly, copy) NSURL *URL;
 
// 該頁面的title
@property (nullable, readonly, copy) NSString *title;
 
// 初始請(qǐng)求該item的請(qǐng)求的URL
@property (readonly, copy) NSURL *initialURL;
 
@end

四WKWebView與JS實(shí)戰(zhàn)

初始化的相關(guān)內(nèi)容在這里不再贅述橄镜,提幾個(gè)常常關(guān)注的點(diǎn)

1.添加對(duì)WKWebView屬性的監(jiān)聽

這里面處理一下常用的三個(gè):loading、title冯乘、estimatedProgress屬性洽胶,分別用于判斷是否正在加載、獲取頁面標(biāo)題裆馒、當(dāng)前頁面載入進(jìn)度:

// 添加KVO監(jiān)聽
    
    [self.webView addObserver:self
                   forKeyPath:@"loading"
                      options:NSKeyValueObservingOptionNew
                      context:nil];
    
    [self.webView addObserver:self
                   forKeyPath:@"title"
                      options:NSKeyValueObservingOptionNew
                      context:nil];
    
    [self.webView addObserver:self
                   forKeyPath:@"estimatedProgress"
                      options:NSKeyValueObservingOptionNew
                      context:nil];

這里不要忘記在界面消失的時(shí)候姊氓,移除監(jiān)聽

 [_webView removeObserver:self forKeyPath:@"loading" context:nil];//移除kvo
 [_webView removeObserver:self forKeyPath:@"title" context:nil];
 [_webView removeObserver:self forKeyPath:@"estimatedProgress" context:nil];

KVO方法:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context
{
    if ([keyPath isEqualToString:@"loading"])
    {
        NSLog(@"loading");
        
    } else if ([keyPath isEqualToString:@"title"])
    {
        self.title = self.webView.title;
    } else if ([keyPath isEqualToString:@"estimatedProgress"])
    {
        NSLog(@"progress: %f", self.webView.estimatedProgress);
        self.progressView.progress = self.webView.estimatedProgress;
    }
    
    // 加載完成
    if (!self.webView.loading)
    {
        [UIView animateWithDuration:0.5 animations:^{
            self.progressView.alpha = 0.0;
        }];
    }
}

2.配置Js與WebView內(nèi)容交互

前面提到了WKUserContentController是用于讓Js注入對(duì)象的,注入對(duì)象后喷好,JS端就可以使用這個(gè)方法:

window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 

用這個(gè)方法發(fā)送數(shù)據(jù)給iOS客戶端翔横,eg:

window.webkit.messageHandlers.senderModel.postMessage({body: 'sender message'});

這里面senderModel就是我們要注入的名稱,注入之后梗搅,就可以在Js端調(diào)用了禾唁,傳數(shù)據(jù)統(tǒng)一通過body來傳遞,類型可以隨意无切,但是只支持OC的一些類型(NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull類型蟀俊。)

iOS端的部分代碼:

config.userContentController = [[WKUserContentController alloc] init];
 
// 注入JS對(duì)象名稱senderModel,當(dāng)JS通過senderModel來調(diào)用時(shí)订雾,我們可以在WKScriptMessageHandler代理中接收到
[config.userContentController addScriptMessageHandler:self name:@"senderModel"];

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message {
  if ([message.name isEqualToString:@"senderModel"]) {
    // 打印所傳過來的參數(shù),只支持NSNumber, NSString, NSDate, NSArray,
    // NSDictionary, and NSNull類型
    //do something
    NSLog(@"%@", message.body);
  }
}

3. WKUIDelegate代理方法

與JS的alert矛洞、confirm洼哎、prompt交互烫映,我們希望用自己的原生界面,而不是JS的噩峦,就可以使用這個(gè)代理類來實(shí)現(xiàn)锭沟。

  • alert警告框函數(shù):
//alert 警告框
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"警告" message:@"調(diào)用alert提示框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    [self presentViewController:alert animated:YES completion:nil];
    NSLog(@"alert message:%@",message);
}
  • confirm確認(rèn)框函數(shù):
//confirm 確認(rèn)框
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"確認(rèn)框" message:@"調(diào)用confirm提示框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:NULL];
    
    NSLog(@"confirm message:%@", message);

}
  • prompt 輸入框函數(shù):
- (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:@"調(diào)用輸入框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.textColor = [UIColor blackColor];
    }];
    
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler([[alert.textFields lastObject] text]);
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
}

4.WKNavigationDelegate

代理方法在第三節(jié)有提到,這里在重復(fù)一下吧

  • 用來追蹤加載過程的方法:
//開始加載時(shí)調(diào)用
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    
}
//當(dāng)內(nèi)容開始返回時(shí)調(diào)用
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    
}
//頁面加載完成之后調(diào)用
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    
}
// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation
{
    
}
  • 頁面跳轉(zhuǎn)的代理方法:
// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到響應(yīng)后识补,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在發(fā)送請(qǐng)求之前族淮,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

以上的方法根據(jù)實(shí)際需求操作即可。

最后

Demo地址:WKWebViewDemo
參考鏈接:WKWebView的新特性與使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凭涂,一起剝皮案震驚了整個(gè)濱河市祝辣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌切油,老刑警劉巖蝙斜,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異澎胡,居然都是意外死亡孕荠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門攻谁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稚伍,“玉大人,你說我怎么就攤上這事戚宦「鍪铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵阁苞,是天一觀的道長(zhǎng)困檩。 經(jīng)常有香客問我,道長(zhǎng)那槽,這世上最難降的妖魔是什么悼沿? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮骚灸,結(jié)果婚禮上糟趾,老公的妹妹穿的比我還像新娘。我一直安慰自己甚牲,他們只是感情好义郑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丈钙,像睡著了一般非驮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雏赦,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天劫笙,我揣著相機(jī)與錄音芙扎,去河邊找鬼。 笑死填大,一個(gè)胖子當(dāng)著我的面吹牛戒洼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播允华,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼圈浇,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了靴寂?” 一聲冷哼從身側(cè)響起磷蜀,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榨汤,沒想到半個(gè)月后蠕搜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡收壕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年妓灌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜜宪。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虫埂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出圃验,到底是詐尸還是另有隱情掉伏,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布澳窑,位于F島的核電站斧散,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏摊聋。R本人自食惡果不足惜鸡捐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望麻裁。 院中可真熱鬧箍镜,春花似錦、人聲如沸煎源。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽手销。三九已至歇僧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锋拖,已是汗流浹背诈悍。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工埂淮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人写隶。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像讲仰,于是被迫代替她去往敵國(guó)和親慕趴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容