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新特性
- 占用內(nèi)存變少了(模擬器加載百度首頁,WKWebView占用22M,UIWebView占用65M)
- 更多的支持HTML5的特性
- 官方宣稱高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢
- 和Safari相同的JavaScript引擎
WKWebView生命周期和跳轉(zhuǎn)代理
#pragma mark - WKNavigationDelegate
// 頁面開始加載時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"頁面開始加載:%s",__FUNCTION__);
}
// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
NSLog(@"內(nèi)容開始返回:%s",__FUNCTION__);
}
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"頁面加載完成:%s",__FUNCTION__);
}
// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"%@",error.debugDescription);
}
// 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// 在收到響應(yīng)后,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationResponsePolicyAllow);
//不允許跳轉(zhuǎn)
//decisionHandler(WKNavigationResponsePolicyCancel);
}
// 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.URL.absoluteString);
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationActionPolicyAllow);
//不允許跳轉(zhuǎn)
//decisionHandler(WKNavigationActionPolicyCancel);
}
前進(jìn) 后退 刷新 進(jìn)度條
//前進(jìn)
webView.goBack()
//后退
webView.goForward()
//刷新
let request = NSURLRequest(URL:webView.URL!)
webView.loadRequest(request)
//監(jiān)聽是否可以前進(jìn)后退,修改btn.enable屬性
webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
//監(jiān)聽加載進(jìn)度
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是不會(huì)出現(xiàn)任何內(nèi)容的,你必須重寫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");
}
// 確認(rèn)框
- (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調(diào)用js方法
WKWebView調(diào)用js方法和UIWebView類似,一個(gè)是evaluateJavaScript,一個(gè)是stringByEvaluatingJavaScriptFromString。獲取返回值的方式不同,WKWebView用的是回調(diào)函數(shù)獲取返回值。
//直接調(diào)用js
webView.evaluateJavaScript("hello()", completionHandler: nil)
//調(diào)用js帶參數(shù)
webView.evaluateJavaScript("hello('ls')", completionHandler: nil)
//調(diào)用js獲取返回值
webView.evaluateJavaScript("getName()") { (any,error) -> Void in
NSLog("%@", any as! String)
}
js調(diào)用app方法
1:注冊handler需要在webView初始化之前;
//配置環(huán)境
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實(shí)現(xiàn)WKScriptMessageHandler委托的方法
// 使用safari模擬器調(diào)試
// 前端需要用 window.webkit.messageHandlers.注冊的方法名.postMessage({body:傳輸?shù)臄?shù)據(jù)} 來給native發(fā)送消息
// 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對象,然后調(diào)用postMessage方法把數(shù)據(jù)傳到app,app通過上一步的方法從message.body中解析方法名和參數(shù)
// 只能傳一個(gè)參數(shù) 可以用json或字典組裝參數(shù),在app里去解析
var message = 'Hello WebKit!'
window.webkit.messageHandlers.webViewApp.postMessage(message);
參考文章
這里僅僅簡要記錄了基本用法。