一肌似、簡(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)有:
- 在性能丹擎、穩(wěn)定性
- WKWebView更多的支持HTML5的特性
- WKWebView更快,占用內(nèi)存可能只有UIWebView的1/3 ~ 1/4
- WKWebView高達(dá)60fps的滾動(dòng)刷新率和豐富的內(nèi)置手勢(shì)
- WKWebView具有Safari相同的JavaScript引擎
- WKWebView增加了加載進(jìn)度屬性
- 將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)化了
差距了幾倍的內(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的新特性與使用