鑒于UIWebView的內存問題,新項目選擇了WKWebView來加載URL詳情頁面,本文將圍繞“加載URL詳情頁面,并確保內部鏈接正常跳轉”的需求,細聊開發過程中遇到的問題。(注:本文不涉及js交互、緩存相關的內容)
一、WKWebView的基本使用
1、加載指定的URL
- (void)gotoWebViewWithUrl:(NSString *)Url
{
WKWebView *webview = [[WKWebView alloc]initWithFrame:self.view.bounds];
[webview loadRequest:[NSURL URLWithString: Url];
}
2、代理
(1) WKNavigationDelegate
// 準備加載頁面
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 內容開始加載
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 頁面加載完成
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 頁面加載失敗
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
// 收到服務器重定向請求
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到響應開始加載后,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在請求開始加載之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
(2) WKUIDelegate
?JS交互時會用到這個代理,本文討論的需求不涉及JS交互,所以這里不在贅述。
二、問題及解決方案
1、黑屏閃現
問題描述: 執行[webview loadRequest:]加載URL頁面時,偶爾會有黑屏閃現的現象。
?解決方案: 在初始化webView時,加載一個空白頁面。
// 加載空白頁
- (void)loadBlankHtml
{
static NSString *blankHtmlStr = @"<!DOCTYPE html>\
<html lang=\"en\">\
<head>\
<meta charset=\"UTF-8\">\
<title>Document</title>\
<style>body{background-color: #111111;}</style>\
</head>\
<body></body>\
</html>";
[self.webView loadHTMLString:blankHtmlStr baseURL:[NSURL URLWithString:kAboutBlank]];
}
2、加載進度、加載超時問題
問題描述:
??點擊webView的某個鏈接跳轉至新的頁面時,會異步的觸發N個請求(多次觸發回調1)來獲取頁面的多個模塊數據,其中某些請求可能不會響應(不會觸發回調2),某些請求可能不會有成功、失敗的回調。
??所以,無法通過監聽請求的開始、結束獲取加載進度,判斷加載超時。
// 回調1: 在請求開始加載之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
// 回調2: 在收到響應開始加載后,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
解決方案:請求觸發回調2方法后才算真正的開始,展示進度條、啟動超時檢測,請求有成功、失敗的返回時,隱藏進度條、停止超時檢測。
// 在收到響應開始加載后,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
if (NO == self.progressView.hidden) {
[self restartOutTimer];
self.progressView.hidden = hide;
}
if (decisionHandler) {
decisionHandler(WKNavigationResponsePolicyAllow);
}
}
3、加載超時處理
問題描述:
?加載超時或沒有網絡時,需要在頁面中告知用戶,同時不影響現有的webView頁面層級關系。(例如,加載頁面后斷網,點擊頁面內鏈接,需要告知用戶沒有網絡,用戶可以通過返回按鈕返回到剛才的頁面)
?解決方案: 加載本地html頁面。
// 在請求開始加載之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSString* requestUrl = [navigationAction.request.URL absoluteString];
// 沒有網絡時,展示本地url頁面
if (self.curNetworkStatus == NetworkNotReachable &&
navigationAction.navigationType != WKNavigationTypeBackForward) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"NoNetwork" ofType:@"html"];
if (![requestUrl isEqualToString:self.rootUrl]) {
[self loadFileURLWithPath:path];
} else {
[self loadHTMLStringWithPath:path];
}
decisionHandler(WKNavigationActionPolicyCancel);
}
}
3、跳轉App Store問題
WKWebView不支持https://itunes.apple.com/cn/app/id******這樣的鏈接跳轉App Store,需要做出如下的處理才能正常跳轉。
// 在請求開始加載之前調用,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
// itunes跳轉鏈接需要單獨處理
if ([[navigationAction.request.URL host] isEqualToString:@"itunes.apple.com"] &&
[[UIApplication sharedApplication] openURL:navigationAction.request.URL]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}