前言
現在多數專案中會有使用webView的情況,過去往往使用UIWebView解決問題,但是由於其各種不便,給開發者帶來了很多麻煩。現在專案中有所使用,所以寫一篇總結,方便以後用到了查詢和使用也為了方便其他同行。
正文
基礎使用
構建和配置
WKWebView是繼承自UIView的,因此構建方式還是很老套的,通常
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
複製程式碼
這個方法就夠用了,第一個引數不多說,按照通常的使用就可以,第二個引數是對webView的配置物件,裡面有很多屬性可以使用,但是這裡我只進行最簡單使用的說明。
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
configuration.preferences.minimumFontSize = 10;//設定最小字型
configuration.preferences.javaScriptEnabled = YES;//是否可以使用JavaScript
configuration.preferences.javaScriptCanOpenWindowsAutomatically = NO;//JS是否可以自動開啟頁面
複製程式碼
以上配置就足夠正常使用,其他的如果專案還有需要,請自己根據需要新增。 然後是對WKWebView的基本設定,
self.webView.scrollView.bounces = NO;
self.webView.navigationDelegate = self;
複製程式碼
設定了取消彈性和代理,需要說明的是由於我們使用的是需要和JS進行互動的webView,所以需要在ViewController中宣告兩個代理WKNavigationDelegate,WKScriptMessageHandler,前者是用來處理webView載入檢視的各種情況的,後者是主要用來處理互動事件的。 最後通過addSubView新增檢視到父檢視上面就可以了,這個時候應該是沒有載入任何頁面的webView。而主要功能載入web網頁,需要使用以下方法:
@property (nonatomic, strong) NSURLRequest *resetUrlRequest;
self.resetUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"你所需要載入的網址"]];
複製程式碼
當然考慮專案中可能會對網址進行拼接,如拼接token,因此強烈建議,將後面的URL構建部分挪到頂上分出來寫。
基本代理相關
常用的有:
//開始載入
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
//載入完成
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
//頁面跳轉失敗
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
//載入報錯,通常來說如果頁面出現不存在等問題,會走這裡,如果需要對空白頁面進行處理,在這裡處理
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
//請求之前,決定是否要跳轉:使用者點選網頁上的連結,需要開啟新頁面時,將先呼叫這個方法。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
//允許頁面跳轉
// NSLog(@"%@=========tw============",navigationAction.request.URL);
//如果是跳轉一個新頁面
if (navigationAction.targetFrame == nil) {
[webView loadRequest:navigationAction.request];
}
decisionHandler(WKNavigationActionPolicyAllow);
}
//接收到相應資料後,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
if (((NSHTTPURLResponse *)navigationResponse.response).statusCode == 200) {
decisionHandler (WKNavigationResponsePolicyAllow);
}else {
decisionHandler(WKNavigationResponsePolicyCancel);
}
}
複製程式碼
還有這些可能需要的
// 主機地址被重定向時呼叫
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
// 當內容開始返回時呼叫
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
// 如果需要證照驗證,與使用AFN進行HTTPS證照驗證是一樣的
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler;
//9.0才能使用,web內容處理中斷時會觸發
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
複製程式碼
到此,基礎的使用結束。
限制使用者選擇以及長按操作
有時候,我們會遇到一個比較頭疼的問題,我們不想讓使用者長按選擇或者有彈窗,那麼這時我們需要新增兩行程式碼來禁止這一系列行為。
//WKWebview 禁止長按(超連結、圖片、文字...)彈出效果
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';" completionHandler:nil];
複製程式碼
值得注意的是,這裡其實是通過呼叫webView直接使用JS程式碼實現的操作,如果有需要還可以實現別的功能,而且這個方法最後有一個執行完畢之後的block,可以實現很多操作。
新增進度條
構建
@property (nonatomic, strong)UIProgressView *progressView;
//新增進度條
self.progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 2, self.view.frame.size.width, self.view.frame.size.height)];
self.progressView.tintColor = UIColorWithRGB(254, 79, 109);
[self.webView addSubview:self.progressView];
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
複製程式碼
監聽
#pragma mark - 進度條
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
[self.progressView setAlpha:1.0f];
[self.progressView setProgress:self.webView.estimatedProgress animated:YES];
if (self.webView.estimatedProgress >= 1.0f) {
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.progressView setAlpha:0.0f];
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:YES];
self.progressView.hidden = YES;
}];
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
複製程式碼
代理中操作
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
self.progressView.hidden = NO;
self.progressView.transform = CGAffineTransformMakeScale(1.0, 1.5);
[self.view bringSubviewToFront:self.progressView]; // 將progress放到最前面
}
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
self.progressView.hidden = YES;
self.title = self.webView.title;
//WKWebview 禁止長按(超連結、圖片、文字...)彈出效果
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
// [self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';" completionHandler:nil];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"%@---------------",error);
self.progressView.hidden = YES;
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"%@-------------------",error);
//載入本地的一個空頁面的操作
//[self sk_loadErrorPage];
}
複製程式碼
返回上級以及popViewController
if ([[self.webView.backForwardList currentItem].title isEqualToString:@"首頁"]) {
[self.navigationController popViewControllerAnimated:YES];
}
if ([self.webView canGoBack]) {
//控制訂單列表中的較多介面折回
if ([[self.webView.backForwardList currentItem].title isEqualToString:@"訂單列表"] &&
[[self.webView.backForwardList backItem].title isEqualToString:@"訂單列表"]) {
[self.webView goToBackForwardListItem:[self.webView.backForwardList backList].firstObject];
}else{
[self.webView goBack];
}
}else{
[self.navigationController popViewControllerAnimated:YES];
}
複製程式碼
可以對H5頁面的標題進行判斷來決定是否跳轉。
重點:JS互動
WKWebView的互動方法和之前的UIWebView其實本質上沒有什麼太大的差別,都是通過傳送方法名找到對應的方法執行對應的操作。我的具體操作如下:
-(void)viewWillAppear:(BOOL)animated{
// self.navigationController.navigationBar.hidden = NO;
if (self.webView) {
if (self.webView.configuration.userContentController.userScripts.count>0) {
//移除所有的監聽
[self removeAllScriptMsgHandle];
}
//對JS呼叫的方法進行監聽,最好集中處理
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"mjxLogin"];
}
}
-(void)viewWillDisappear:(BOOL)animated{
[self removeAllScriptMsgHandle];
}
- (void)dealloc{
//移除監聽和代理
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
[self.webView setNavigationDelegate:nil];
[self.webView setUIDelegate:nil];
}
-(void)removeAllScriptMsgHandle{
//移除監聽,不移除一定會報錯
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"mjxLogin"];
}
複製程式碼
對監聽的處理的代理
//用來接收js呼叫本地方法的攔截器
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
// NSLog(@"%@------mes------",message.body);
//分享,多引數的情況
if ([message.name isEqualToString:@"mjxShare"]) {
NSDictionary *messageDic = message.body;
[self shareGoodsWithTitle:messageDic[@"title"] withContent:messageDic[@"content"] withUrl:messageDic[@"url"] withImage:messageDic[@"img"]];
}
//申請試用,帶一個引數的情況
if ([message.name isEqualToString:@"mjxApply"]) {
NSDictionary *messageDic = message.body;
[self requestApplyGoods:messageDic[@"trade_sn"]];
}
//彈出錯誤資訊
if ([message.name isEqualToString:@"errorAlert"]) {
[SKHUD showErrorWithStatus:message.body];
}
//儲存二維碼
if ([message.name isEqualToString:@"codeImg"]) {
[SVProgressHUD show];
NSDictionary *messageDic = message.body;
NSURL *url = [NSURL URLWithString:messageDic[@"codeImgUrl"]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img;
img = [UIImage imageWithData:data];
UIImageWriteToSavedPhotosAlbum( img, self,@selector(imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:) , NULL);
}
}
複製程式碼
到此,相關使用全部結束,希望喜歡活有用的話,能夠點贊或者評論支援,謝謝。