1.背景
WKWebView是蘋果在iOS 8中引入的新組件坚俗,目的是給出一個新的高性能的WebView解決方案措译,擺脫過去 UIWebView的老娶眷、舊、笨重枉层,特別是內(nèi)存占用量巨大的問題泉褐,它使用Nitro JavaScript引擎,這意味著所有第三方瀏覽器運行JavaScript將會跟safari一樣快鸟蜡。
WKWebView對比UIWebView
1. WKWebView的內(nèi)存開銷要比UIWebView小很多
2. 擁有高達(dá)60FPS滾動刷新率及內(nèi)置手勢
3. 支持了更多的HTML5特性
4. html頁面和WKWebView交互更方便
5. Safari相同的JavaScript引擎
6. 提供常用的屬性膜赃,如加載網(wǎng)頁進度的屬性estimatedProgress
2.基本使用
2.1. 初始化
除了-init初始化方法之外,WebKit還提供了另外一個初始化方法:-initWithFrame:configuration: 揉忘,第二個參數(shù)configuration提供了豐富的可配置屬性或链,我們目前只用到了其中的WKPreferences骇扇,作用下面會說到
2.2. 加載請求
一共有4個加載api:
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0));
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));
我們項目中用到的是前2個api练般,第一個api主要是用來訪問iOS9及以上設(shè)備的網(wǎng)絡(luò)請求和iOS9以下的所有請求齿风,第二個api用于iOS9及以上設(shè)備的本地資源訪問。
2.3. 代理
WKWebview主要涉及到兩個delegate:
WKNavigationDelegate和WKUIDelegateWKNavigationDelegate一般涉及到頁面加載狀態(tài)的回調(diào):
// 頁面開始加載時調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 當(dāng)內(nèi)容開始返回時調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 頁面加載失敗時調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
// 接收到服務(wù)器跳轉(zhuǎn)請求之后調(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ā)送請求之前狂丝,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
WKUIDelegate一般用于JS調(diào)用客戶端彈出框(警告框、確認(rèn)框哗总、輸入框)的時候進行相應(yīng)的自定義操作几颜,項目中沒有涉及到,就不多闡述讯屈。
2.4. 客戶端與JS交互(WKWebVIew調(diào)用js)
區(qū)別于UIWebView中的-stringByEvaluatingJavaScriptFromString:同步方法蛋哭,WKWebView中調(diào)用js的api為-evaluateJavaScript:completionHandler: ,completionHandler是異步回調(diào)的block
2.5. JS與客戶端交互
首先客戶端通過WKUserContentController類的-addScriptMessageHandler:name:方法添加響應(yīng)指定name方法的代理對象涮母,然后js通過以下方式調(diào)用oc方法:window.webkit.messageHandlers..postMessage()谆趾,js發(fā)起后,代理方法-userContentController:didReceiveScriptMessage:被調(diào)用叛本。另:addScriptMessageHandler之后要記得removeScriptMessageHandlerForName沪蓬。
3.遇到的問題:
3.1. 與UIWebview的webView:shouldStartLoadWithRequest:navigationType:代理相對應(yīng)的代理方法是webView:decidePolicyForNavigationAction:decisionHandler:而不是webView:didStartProvisionalNavigation:
3.2. 加載本地html問題
ios9及以上加載本地html資源的時候不能通過loadRequest:這個api進行請求,只能通過iOS 9新接口? ? -loadFIleURL:allowingReadAccessToURL: 炮赦,此處需要注意傳入的第一個參數(shù)url必須得是fileUrl格式的,即前綴得是file:// 格式的本地路徑样勃,第二個參數(shù)要是訪問文件的文件夾路徑吠勘。
iOS 9 以下解決方案:先將本地 HTML 文件的數(shù)據(jù) copy 到 tmp 目錄中性芬,然后再使用 loadRequest 來加載。我們項目中則是通過移動整個webResource文件夾到tmp目錄解決剧防。? 考慮到iOS8中WKWebView存在較多問題植锉,后來我們在iOS中統(tǒng)一采用UIWebview方案。
3.3. 跨域問題
跨域訪問峭拘,簡單來說就是 A 網(wǎng)站的 javascript 代碼試圖訪問 B 網(wǎng)站俊庇,包括提交內(nèi)容和獲取內(nèi)容。由于安全原因鸡挠,跨域訪問是被各大瀏覽器所默認(rèn)禁止的辉饱。
CORS(一個W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing))允許瀏覽器向跨源服務(wù)器拣展,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制彭沼。
WKKit默認(rèn)強制實現(xiàn)CORS,在不涉及服務(wù)端改動的情況下通過KVC修改屬性值解決[config.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"]