Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content to your app. Do not use UIWebView or WebView.
WKWebView新特性
- 占用內存變少了(模擬器加載百度首頁,WKWebView占用22M,UIWebView占用65M)
- 更多的支持HTML5的特性
- 官方宣稱高達60fps的滾動刷新率以及內置手勢
- 和Safari相同的JavaScript引擎
WKWebView生命周期和跳轉代理
#pragma mark - WKNavigationDelegate
// 頁面開始加載時調用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"頁面開始加載:%s",__FUNCTION__);
}
// 當內容開始返回時調用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
NSLog(@"內容開始返回:%s",__FUNCTION__);
}
// 頁面加載完成之后調用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"頁面加載完成:%s",__FUNCTION__);
}
// 頁面加載失敗時調用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"%@",error.debugDescription);
}
// 接收到服務器跳轉請求之后調用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// 在收到響應后,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允許跳轉
decisionHandler(WKNavigationResponsePolicyAllow);
//不允許跳轉
//decisionHandler(WKNavigationResponsePolicyCancel);
}
// 在發送請求之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.URL.absoluteString);
//允許跳轉
decisionHandler(WKNavigationActionPolicyAllow);
//不允許跳轉
//decisionHandler(WKNavigationActionPolicyCancel);
}
前進 后退 刷新 進度條
//前進
webView.goBack()
//后退
webView.goForward()
//刷新
let request = NSURLRequest(URL:webView.URL!)
webView.loadRequest(request)
//監聽是否可以前進后退,修改btn.enable屬性
webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
//監聽加載進度
webView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)
//重寫self的kvo方法
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if (keyPath == "loading") {
gobackBtn.enabled = webView.canGoBack
forwardBtn.enabled = webView.canGoForward
}
if (keyPath == "estimatedProgress") {
//progress是UIProgressView
progress.hidden = webView.estimatedProgress==1
progress.setProgress(Float(webView.estimatedProgress), animated: true)
}
}
JS中alert攔截
在WKWebview中,js的alert是不會出現任何內容的,你必須重寫WKUIDelegate委托的runJavaScriptAlertPanelWithMessage message方法,自己處理alert。類似的還有Confirm和prompt,這里我只以alert為例。
// 輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{
completionHandler(@"hello");
}
// 確認框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{
completionHandler(YES);
}
// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:webView.title message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
app調用js方法
WKWebView調用js方法和UIWebView類似,一個是evaluateJavaScript,一個是stringByEvaluatingJavaScriptFromString。獲取返回值的方式不同,WKWebView用的是回調函數獲取返回值。
//直接調用js
webView.evaluateJavaScript("hello()", completionHandler: nil)
//調用js帶參數
webView.evaluateJavaScript("hello('ls')", completionHandler: nil)
//調用js獲取返回值
webView.evaluateJavaScript("getName()") { (any,error) -> Void in
NSLog("%@", any as! String)
}
js調用app方法
1:注冊handler需要在webView初始化之前;
//配置環境
WKWebViewConfiguration *conf = [[WKWebViewConfiguration alloc] init];
userContentController = [[WKUserContentController alloc] init];
conf.userContentController = userContentController;
// 注冊方法
[userContentController addScriptMessageHandler:self name:@"webViewHandle"];
// 初始化
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:conf];
2:處理handler委托。ViewController實現WKScriptMessageHandler委托的方法
// 使用safari模擬器調試
// 前端需要用 window.webkit.messageHandlers.注冊的方法名.postMessage({body:傳輸的數據} 來給native發送消息
// window.webkit.messageHandlers.webViewHandle.postMessage("Hello WebKit!")
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
NSLog(@"%@ -- %@",message.name, message.body);
}
3:通過 window.webkit.messageHandlers.webViewApp找到之前注冊的handler對象,然后調用postMessage方法把數據傳到app,app通過上一步的方法從message.body中解析方法名和參數
// 只能傳一個參數 可以用json或字典組裝參數,在app里去解析
var message = 'Hello WebKit!'
window.webkit.messageHandlers.webViewApp.postMessage(message);
參考文章
這里僅僅簡要記錄了基本用法。