IOS進階之WKWebView

前言

Xcode8發佈之後,編譯器開始不支持IOS7,因此不少應用在適配IOS10以後都不在適配IOS7了,其中包括了不少大公司,網易新聞,滴滴出行等。所以,咱們公司的應用也打算淘汰IOS7。html

支持到IOS8,第一個要改的天然是用WKWebView替換原來的UIWebView。WKWebView有不少明顯優點:前端

  • 更多的支持HTML5的特性git

  • 官方宣稱的高達60fps的滾動刷新率以及內置手勢github

  • 將UIWebViewDelegate與UIWebView拆分紅了14類與3個協議,之前不少不方便實現的功能得以實現。文檔web

  • Safari相同的JavaScript引擎json

  • 佔用更少的內存服務器

 

UIWebView

 

WKWebView

 
所以,使用WKWebView替換UIWebView仍是頗有必要的。

基本使用方法

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 }
 
 
二、WKUIDelegate中的代理方法
 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 }
 
三、WKNavigationDelegate中的代理方法
 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 }

OC與JS交互

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 
 
H5代碼:
 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

WebViewJavascriptBridge

通常來講,一個好的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下來使用。

相關文章
相關標籤/搜索