IOS中WKWebView 簡單使用

weixin_34391445發表於2016-11-03

iOS開發之 WKWebVeiw使用

想用UIWebVeiw做的,但是突然想起來在iOS8中出了一個新的WKWebView,算是UIWebVeiw的升級版。本著對新事物的好奇,就上網查了一下,但是找了好多個都沒說的多了詳細,於是就問谷歌,找文件,看看使用方法,試用了一下,果然不錯,記錄下來,大家分享!

WKWebView的特點:

效能高,穩定性好,佔用的記憶體比較小,
支援JS互動
支援HTML5 新特性
可以新增進度條(然並卵,不好用,還是習慣第三方的)。
支援內建手勢,
據說高達60fps的重新整理頻率(不卡)

建立

  • 匯入Wbkit這個類庫(WKWebVeiw包含在裡面的)
  • 遵守協議(一般前兩個就行啦,第三個主要是與JS相關的東西,這個協議中包含一個必須實現的方法,這個方法是提高App與web端互動的關鍵,它可以直接將接收到的JS指令碼轉為OC或Swift物件--網上大神說的,我沒用過。)
@interface ViewController : UIViewController<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
  • 建立個WebView的物件
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
 [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]]]; 
[self.view addSubview:webView];

這裡有個注意點,網址一定要寫完整,加上https://
我剛開始懶,沒有加,屋裡怎麼試都載入不出來,顯示個白屏!!血的教訓啊!!

WKWebView有三個委託

WKWebView代理有兩個,是WKNavigationDelegate
和WKUIDelegate
,可以根據需要來決定用那些方法(當然使用之前不要忘了遵守協議)。
他們兩個的代理方法有好多個,不過有的不常用就不寫了,需要的自己點進去看一下就行啦。。。

1. WKNavigationDelegate

  • 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;
  • WKNavigtionDelegate來進行頁面跳轉
// 接收到伺服器跳轉請求之後再執行
- (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

//1.建立一個新的WebVeiw
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures   *)windowFeatures;
//2.WebVeiw關閉(9.0中的新方法)
- (void)webViewDidClose:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
//3.顯示一個JS的Alert(與JS互動)
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//4.彈出一個輸入框(與JS互動的)
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
//5.顯示一個確認框(JS的)
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

3.WKScriptMessageHandler

這個協議中包含一個必須實現的方法,這個方法是提高App與web端互動的關鍵,它可以直接將接收到的JS指令碼轉為OC或Swift物件。(當然,在UIWebView也可以通過“曲線救國”的方式與web進行互動,著名的Cordova框架就是這種機制)
// 從web介面中接收到一個指令碼時呼叫

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

ios9以前版本讀取本地HTML的問題

當使用loadRequest來讀取本地的HTML時,WKWebView是無法讀取成功的,後臺會出現如下的提示:Could not create a sandbox extension for /
原因是WKWebView是不允許通過loadRequest的方法來載入本地根目錄的HTML檔案。而在iOS9的SDK中加入了以下方法來載入本地的HTML檔案:[WKWebView loadFileURL:allowingReadAccessToURL:]
但是在iOS9以下的版本是沒提供這個便利的方法的。以下為解決方案的思路,就是在iOS9以下版本時,先將本地HTML檔案的資料copy到tmp目錄中,然後再使用loadRequest來載入。但是如果在HTML中加入了其他資原始檔,例如js,css,image等必須一同copy到temp中。這個是最蛋疼的事情了。

解決方法如下
1.Objective-C:

//將檔案copy到tmp目錄- (NSURL *)fileURLForBuggyWKWebView8:(NSURL *)fileURL { NSError *error = nil; if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) { return nil; } // Create "/temp/www" directory NSFileManager *fileManager= [NSFileManager defaultManager]; NSURL *temDirURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"www"]; [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error]; NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent]; // Now copy given file to the temp directory [fileManager removeItemAtURL:dstURL error:&error]; [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error]; // Files in "/temp/www" load flawlesly :) return dstURL;}//呼叫邏輯 NSString *path = [[NSBundle mainBundle] pathForResource:@"indexoff" ofType:@"html"]; if(path){ if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) { // iOS9. One year later things are OK. NSURL *fileURL = [NSURL fileURLWithPath:path]; [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL]; } else { // iOS8. Things can be workaround-ed // Brave people can do just this // fileURL = try! pathForBuggyWKWebView8(fileURL) // webView.loadRequest(NSURLRequest(URL: fileURL)) NSURL *fileURL = [self.fileHelper fileURLForBuggyWKWebView8:[NSURL fileURLWithPath:path]]; NSURLRequest *request = [NSURLRequest requestWithURL:fileURL]; [self.webView loadRequest:request]; } }

2.Swift

//將檔案copy到tmp目錄func fileURLForBuggyWKWebView8(fileURL: NSURL) throws -> NSURL { // Some safety checks var error:NSError? = nil; if (!fileURL.fileURL || !fileURL.checkResourceIsReachableAndReturnError(&error)) { throw error ?? NSError( domain: "BuggyWKWebViewDomain", code: 1001, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")]) } // Create "/temp/www" directory let fm = NSFileManager.defaultManager() let tmpDirURL = NSURL.fileURLWithPath(NSTemporaryDirectory()).URLByAppendingPathComponent("www") try! fm.createDirectoryAtURL(tmpDirURL, withIntermediateDirectories: true, attributes: nil) // Now copy given file to the temp directory let dstURL = tmpDirURL.URLByAppendingPathComponent(fileURL.lastPathComponent!) let _ = try? fileMgr.removeItemAtURL(dstURL) try! fm.copyItemAtURL(fileURL, toURL: dstURL) // Files in "/temp/www" load flawlesly :) return dstURL}//方法呼叫 var filePath = NSBundle.mainBundle().pathForResource("file", ofType: "pdf") if #available(iOS 9.0, *) { // iOS9. One year later things are OK. webView.loadFileURL(fileURL, allowingReadAccessToURL: fileURL) } else { // iOS8. Things can be workaround-ed // Brave people can do just this // fileURL = try! pathForBuggyWKWebView8(fileURL) // webView.loadRequest(NSURLRequest(URL: fileURL)) do { fileURL = try fileURLForBuggyWKWebView8(fileURL) webView.loadRequest(NSURLRequest(URL: fileURL)) } catch let error as NSError { print("Error: " + error.debugDescription) } }

WKWebView - WKNavigationDelegate使用

特別提醒一點,在使用以下delegate的方法時

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

需執行decisionHandler的block。

例如:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSURLRequest *request = navigationAction.request; WMPageActionType actionType = ActionTypeNone; WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow; if([request.URL.absoluteString hasPrefix:OC_CLOSE_REQUEST]){ actionType = ActionTypeClose; actionPolicy = WKNavigationActionPolicyCancel; } if(self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(webView:action:type:)]) { [self.actionDelegate webView:webView action:navigationAction type:actionType]; } //這句是必須加上的,不然會異常 decisionHandler(actionPolicy);}

WKWebView-JS執行方法

WKWebView JS執行方法與UIWebView不一樣了。

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler;

completionHandler 擁有兩個引數,一個是返回錯誤,一個可以返回執行指令碼後的返回值

相關文章