• IOS进阶之WKWebView


    前言

    Xcode8发布以后,编译器开始不支持IOS7,所以很多应用在适配IOS10之后都不在适配IOS7了,其中包括了很多大公司,网易新闻,滴滴出行等。因此,我们公司的应用也打算淘汰IOS7。

    支持到IOS8,第一个要改的自然是用WKWebView替换原来的UIWebView。WKWebView有很多明显优势:

    • 更多的支持HTML5的特性

    • 官方宣称的高达60fps的滚动刷新率以及内置手势

    • 将UIWebViewDelegate与UIWebView拆分成了14类与3个协议,以前很多不方便实现的功能得以实现。文档

    • Safari相同的JavaScript引擎

    • 占用更少的内存

    UIWebView

    WKWebView

     
    因此,使用WKWebView替换UIWebView还是很有必要的。

    基本使用方法

    WKWebView有两个delegate,WKUIDelegate 和 WKNavigationDelegate。WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。

    1、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 }
     
     
    2、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 }
     
    3、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交互。简单的说就是先注册约定好的方法,然后再调用。

    1、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

    2、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

    3、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> 

    注意点

    1、addScriptMessageHandler要和removeScriptMessageHandlerForName配套出现,否则会造成内存泄漏。

    2、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下来使用。

  • 相关阅读:
    CentOS的SSH,Putty配置说明
    关于QString::toWCharArray 无法解析的外部符号
    CentOS最常用命令及快捷键整理
    Ali相关面试题
    C#几个例子[静态构造函数,继承,虚方法]
    SQL 2005 中查询或执行另外的数据库操作的方法
    DataTable Select Top
    SQL中行列转换 Pivot UnPivot
    ASP.NET页面生命周期描述
    Jquery checkbox, select 取值
  • 原文地址:https://www.cnblogs.com/francisblogs/p/5999568.html
Copyright © 2020-2023  润新知