在開發過程中,iOS 中實現加載 web 頁面主要有兩種控件,UIWebView 和 WKWebview,兩種控件對應具體的實現方法不同。WKWebView是蘋果公司在iOS8系統推出的,這里主要概述WebKit中更新的WKWebView控件的新特性與使用方法,以及小編在開發過程中踩的坑。
一、相比於UIWebView的優勢:
- 在性能、穩定性、占用內存方面有很大提升;
- 允許JavaScript的Nitro庫加載並使用(UIWebView中限制)
- 增加加載進度屬性:estimatedProgress,不用在自己寫假進度條了
- 支持了更多的HTML的屬性
二、WKWebview的常用屬性
@property (nullable, nonatomic, readonly, copy) NSString *title; @property (nullable, nonatomic, readonly, copy) NSURL *URL; @property (nonatomic, readonly, getter=isLoading) BOOL loading; //加載進度 @property (nonatomic, readonly) double estimatedProgress;
三、WKWebview的常用方法
- (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));
四、WKNavigationDelegate代理的方法
#pragma mark - WKNavigationDelegate /* 頁面開始加載 */ - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ NSLog(@"頁面開始加載"); } /* 開始返回內容 */ - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ NSLog(@"開始返回內容"); } /* 頁面加載完成 */ - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ NSLog(@"頁面加載完成"); } /* 頁面加載失敗 */ - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ NSLog(@"頁面加載失敗"); } /* 在發送請求之前,決定是否跳轉 */ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ //允許跳轉 decisionHandler(WKNavigationActionPolicyAllow); //不允許跳轉 //decisionHandler(WKNavigationActionPolicyCancel); } /* 在收到響應后,決定是否跳轉 */ - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ NSLog(@"%@",navigationResponse.response.URL.absoluteString); //允許跳轉 decisionHandler(WKNavigationResponsePolicyAllow); //不允許跳轉 //decisionHandler(WKNavigationResponsePolicyCancel); }
五、小編的實例Demo
首先遵守協議:
<WKUIDelegate, WKNavigationDelegate>
其次創建一個WKWebView
#pragma mark - 創建webView - (void)createWebView{ WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; config.selectionGranularity = WKSelectionGranularityDynamic; config.allowsInlineMediaPlayback = YES; WKPreferences *preferences = [WKPreferences new]; //是否支持JavaScript preferences.javaScriptEnabled = YES; //不通過用戶交互,是否可以打開窗口 preferences.javaScriptCanOpenWindowsAutomatically = YES; config.preferences = preferences; self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:self.webView]; /* 加載服務器url的方法*/ NSString *url = @"https://www.baidu.com"; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; [self.webView loadRequest:request]; self.webView.navigationDelegate = self; self.webView.UIDelegate = self; }
這樣就可以在webView中正常加載百度首頁了。
不過,在開發中有時遇到網絡不佳的時候,想給用戶顯示一個加載網頁的進度,加載完成后,想再navigation中顯示網頁的標題,就需要對WKWebView的"estimatedProgress"和
"title"進行監聽了。
首先創建一個進度條
- (void)createProgressView{ self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 88, SCREEN_WIDTH, 2)]; self.progressView.progressViewStyle = UIProgressViewStyleDefault; self.progressView.tintColor = [UIColor blueColor]; self.progressView.trackTintColor = [UIColor greenColor]; [self.view addSubview:self.progressView]; }
讓webView對“進度”和“標題”進行監聽
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
最后,完成對KVO的回調
#pragma mark - KVO回饋 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ if ([keyPath isEqualToString:@"estimatedProgress"]) { double progress = _webView.estimatedProgress; self.progressView.alpha = 1.0f; [self.progressView setProgress:progress animated:YES]; if(progress >= 1){ [UIView animateWithDuration:0.25 delay:0.25 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.progressView.alpha = 0.0f; } completion:^(BOOL finished) { [self.progressView setProgress:0.0f animated:NO]; }]; } if ([change[@"new"] floatValue] <[change[@"old"] floatValue]) { return; } if ([change[@"new"]floatValue] == 1.0) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ }); } } else if ([keyPath isEqualToString:@"title"]){ self.title = change[@"new"]; } }
這樣就實現了對加載進度的顯示了。