Xcode8發佈之後,編譯器開始不支持IOS7,因此不少應用在適配IOS10以後都不在適配IOS7了,其中包括了不少大公司,網易新聞,滴滴出行等。所以,咱們公司的應用也打算淘汰IOS7。html
支持到IOS8,第一個要改的天然是用WKWebView
替換原來的UIWebView
。WKWebView有不少明顯優點:前端
更多的支持HTML5的特性git
官方宣稱的高達60fps的滾動刷新率以及內置手勢github
將UIWebViewDelegate與UIWebView拆分紅了14類與3個協議,之前不少不方便實現的功能得以實現。文檔web
Safari相同的JavaScript引擎json
佔用更少的內存服務器
WKWebView有兩個delegate,WKUIDelegate 和 WKNavigationDelegate。WKNavigationDelegate主要處理一些跳轉、加載處理操做,WKUIDelegate主要處理JS腳本,確認框,警告框等。所以WKNavigationDelegate更加經常使用。app
一、WKWebView的初始化框架
1 - (void)viewDidLoad 2 { 3 [super viewDidLoad]; 4 webView = [[WKWebView alloc] initWithFrame:self.view.frame]; 5 [self.view addSubview:webView]; 6 webView.UIDelegate = self; 7 webView.navigationDelegate = self; 8 [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]]; 9 }
1 #pragma mark - WKUIDelegate 2 // 建立一個新的WebView 3 - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{ 4 return [[WKWebView alloc]init]; 5 } 6 7 // 輸入框 8 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{ 9 completionHandler(@"http"); 10 } 11 12 // 確認框 13 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{ 14 completionHandler(YES); 15 } 16 17 // 警告框 18 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{ 19 NSLog(@"%@",message); 20 completionHandler(); 21 }
1 #pragma mark - WKNavigationDelegate 2 // 頁面開始加載時調用 3 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ 4 5 } 6 7 // 當內容開始返回時調用 8 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ 9 10 } 11 12 // 頁面加載完成以後調用 13 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ 14 15 } 16 17 // 頁面加載失敗時調用 18 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ 19 20 } 21 22 // 接收到服務器跳轉請求以後調用 23 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{ 24 25 } 26 27 // 在收到響應後,決定是否跳轉 28 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ 29 NSLog(@"%@",navigationResponse.response.URL.absoluteString); 30 //容許跳轉 31 decisionHandler(WKNavigationResponsePolicyAllow); 32 //不容許跳轉 33 //decisionHandler(WKNavigationResponsePolicyCancel); 34 } 35 36 // 在發送請求以前,決定是否跳轉 37 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ 38 NSLog(@"%@",navigationAction.request.URL.absoluteString); 39 //容許跳轉 40 decisionHandler(WKNavigationActionPolicyAllow); 41 //不容許跳轉 42 //decisionHandler(WKNavigationActionPolicyCancel); 43 }
WKWebview提供了API實現js交互 不須要藉助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController實現js native交互。簡單的說就是先註冊約定好的方法,而後再調用。異步
一、JS調用OC方法
1 @interface ViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>{ 2 WKWebView * webView; 3 WKUserContentController* userContentController; 4 } 5 @end 6 @implementation ViewController 7 8 - (void)viewDidLoad { 9 [super viewDidLoad]; 10 //配置環境 11 WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init]; 12 userContentController =[[WKUserContentController alloc]init]; 13 configuration.userContentController = userContentController; 14 webView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:configuration]; 15 //註冊方法 16 [userContentController addScriptMessageHandler:self name:@"sayhello"];//註冊一個name爲sayhello的js方法 17 18 [self.view addSubview:webView]; 19 webView.UIDelegate = self; 20 webView.navigationDelegate = self; 21 [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]]; 22 } 23 - (void)dealloc{ 24 //這裏須要注意,前面增長過的方法必定要remove掉。 25 [userContentController removeScriptMessageHandlerForName:@"sayhello"]; 26 } 27 #pragma mark - WKScriptMessageHandler 28 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ 29 NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo); 30 } 31 @end
二、WKDelegateController.h代碼:
1 #import <UIKit/UIKit.h> 2 #import <WebKit/WebKit.h> 3 @protocol WKDelegate <NSObject> 4 5 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message; 6 7 @end 8 9 @interface WKDelegateController : UIViewController <WKScriptMessageHandler> 10 11 @property (weak , nonatomic) id<WKDelegate> delegate; 12 @end
三、WKDelegateController.m代碼:
1 #import "WKDelegateController.h" 2 3 @interface WKDelegateController () 4 5 @end 6 7 @implementation WKDelegateController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 } 12 13 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ 14 if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) { 15 [self.delegate userContentController:userContentController didReceiveScriptMessage:message]; 16 } 17 } 18 19 20 @end
1 <html> 2 <head> 3 <script> 4 function say() 5 { 6 //前端須要用 window.webkit.messageHandlers.註冊的方法名.postMessage({body:傳輸的數據} 來給native發送消息 7 window.webkit.messageHandlers.sayhello.postMessage({body: 'hello world!'}); 8 } 9 </script> 10 </head> 11 <body> 12 <h1>hello world</h1> 13 <button onclick="say()">say hello</button> 14 </body> 15 16 </html>
一、addScriptMessageHandler
要和removeScriptMessageHandlerForName
配套出現,不然會形成內存泄漏。
二、h5只能傳一個參數,若是須要多個參數就須要用字典或者json組裝。
OC調用JS方法
1 - (void)webView:(WKWebView *)tmpWebView didFinishNavigation:(WKNavigation *)navigation{ 2 3 //say()是JS方法名,completionHandler是異步回調block 4 [webView evaluateJavaScript:@"say()" completionHandler:^(id _Nullable result, NSError * _Nullable error) { 5 NSLog(@"%@",result); 6 }]; 7 8 }
通常來講,一個好的UI總有一個大神會開發出一個好的第三方封裝框架。WebViewJavascriptBridge的做者也作了一套支持WKWebView與JS交互的第三方框架:WKWebViewJavascriptBridge。
cocoaPods: pod 'WebViewJavascriptBridge', '~> 5.0.5'
github地址:https://github.com/marcuswestin/WebViewJavascriptBridge
主要方法:
1 //初始化方法 2 + (instancetype)bridgeForWebView:(WKWebView*)webView; 3 4 + (void)enableLogging; 5 6 //註冊函數名 7 - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; 8 9 //調用函數名 10 - (void)callHandler:(NSString*)handlerName; 11 - (void)callHandler:(NSString*)handlerName data:(id)data; 12 - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; 13 14 //重置 15 - (void)reset; 16 17 //設置WKNavigationDelegate 18 - (void)setWebViewDelegate:(id<WKNavigationDelegate>)webViewDelegate;
基本的實現方法和上面寫的差很少,就是封裝了一下,有興趣的童鞋能夠本身pod下來使用。