• ios WKWebView 与 JS 交互实战技巧


    一、WKWebView

    由于Xcode8发布之后,编译器开始不支持iOS 7了,这样我们的app也改为最低支持iOS 8.0,既然需要与web交互,那自然也就选择使用了 iOS 8.0之后 才推出的新控件 WKWebView.

    相比与 UIWebView, WKWebView 存在很多优势:

    • 支持更多的HTML5的特性
    • 高达60fps滚动刷新频率与内置手势
    • 与Safari相容的JavaScript引擎
    • 在性能、稳定性方面有很大提升占用内存更少 协议方法及功能都更细致
    • 可获取加载进度等。

    二、WKWebView 用法简介

    注:本文主要说明WKWebView与JS的交互,这里只简单介绍WKWebView基础用法,其他具体详细用法详见官方文档

    需要引入WebKit

    #import <webkit webkit.h="">

    实例化

    /*! @abstract Returns a web view initialized with a specified frame and
     configuration.
     @param frame The frame for the new web view.
     @param configuration The configuration for the new web view.
     @result An initialized web view, or nil if the object could not be
     initialized.
     @discussion This is a designated initializer. You can use
     @link -initWithFrame: @/link to initialize an instance with the default
     configuration. The initializer copies the specified configuration, so
     mutating the configuration after invoking the initializer has no effect
     on the web view.
     */
    - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

    加载HTML页面

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
    WKWebView *webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
    [webView loadRequest:request];
    [self.view addSubview:webView];

    这里只需load即可 与UIWebView使用相同,下面简单介绍一下两个常用的代理

    三、WKWebView 代理

    WKWebView 有两个代理:

    
    /*! @abstract The web view's navigation delegate. */
    @property (nullable, nonatomic, weak) id <wknavigationdelegate> navigationDelegate;
    
    /*! @abstract The web view's user interface delegate. */
    @property (nullable, nonatomic, weak) id <wkuidelegate> UIDelegate;

    WKNavigationDelegate 协议

    WKNavigationDelegate主要处理页面跳转相关事件

    //判断链接是否允许跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
    
    //拿到响应后决定是否允许跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
    
    //链接开始加载时调用
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    
    //收到服务器重定向时调用
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    
    //加载错误时调用
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    
    //当内容开始到达主帧时被调用(即将完成)
    - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
    
    //加载完成
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
    
    //在提交的主帧中发生错误时调用
    - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    
    //当webView需要响应身份验证时调用(如需验证服务器证书)
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
    
    //当webView的web内容进程被终止时调用。(iOS 9.0之后)
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

    WKUIDelegate 协议

    WKUIDelegate主要处理一些页面上的事件,如警告框、对话框等。

    常用的方法:

    //接收到警告面板
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
    
    //接收到确认面板
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
    
    //接收到输入框
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;

    四、WKWebView与JS的交互

    交互方式

    iOS 8.0 之前 用UIWebView时,只能OC调用JS代码,但JS是无法直接调用OC代码,需要通过约定特殊请求,并通过UIWebView的协议方法拦截请求的方式来实现JS对OC的调用。

    但使用 WKWebView 就方便的多,可以直接添加对约定的ScriptMessage(直译为 脚本信息,本文暂定为JS事件)的监听,即可实现JS调用OC。所有的操作都是通过WKUserContentController来处理的

    如何获取WKUserContentController

    WKUserContentController 是 WKWebViewConfiguration 的属性,而WKWebViewConfiguration 是 WKWebView 的属性(也就是在WKWebView实例化的时候传入的configuration)

    WKUserContentController *conntentController = self.webView.configuration.userContentController;

    下面将详细介绍WKUserContentController。

    五、WKUserContentController & JS调用OC

    /*! A WKUserContentController object provides a way for JavaScript to post
     messages to a web view.
     The user content controller associated with a web view is specified by its
     web view configuration.
     */
    WK_EXTERN API_AVAILABLE(macosx(10.10), ios(8.0))
    @interface WKUserContentController : NSObject <nscoding>
    WKUserContentController提供了JavaScript给Web view 发消息的途径

    相关方法介绍

    //添加ScriptMessage(JS事件)和处理者
    - (void)addScriptMessageHandler:(id <wkscriptmessagehandler>)scriptMessageHandler name:(NSString *)name;
    
    //移除指定ScriptMessage(JS事件)监听
    - (void)removeScriptMessageHandlerForName:(NSString *)name;

    JS调用OC

    ScriptMessage(JS事件)的添加删除

    首先在JS代码中加入对事先约定好的 ScriptMessage(JS事件)的调用

    window.webkit.messageHandlers.<事件名>.postMessage(需要传递的数据)

    同时OC端则需要加入对此JS事件的监听

    例如:传递一个名为 @”closeWindow” 的消息

    window.webkit.messageHandlers.closeWindow.postMessage()

    OC端添加一个名为 @”closeWindow” 的 JS的监听

    [conntentController addScriptMessageHandler:self name:@"closeWindow"];

    这里就添加了对 @”closeWindow” 的监听。但是当截获 此JS事件的时候需要作何处理,则需要在对应的协议方法中实现,则scriptMessageHandler需要实现协议WKScriptMessageHandler 会在稍后介绍。

    移除对一个名为 @”closeWindow” 的JS事件的监听

    [conntentController removeScriptMessageHandlerForName:@"closeWindow"];

    WKScriptMessageHandler 协议

    //当接收到一个ScriptMessage(JS事件)时调用
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

    例如:处理名为 @”closeWindow” 的事件

    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
    {
        //message.name 为 ScriptMessage 的名称
        if ([message.name isEqualToString:@"closeWindow"]) {
            //做处理 do something
            //message.body 为此 ScriptMessage 传递的消息内容
        }
    }

    六、OC调用JS

    与UIWebView一样WKWebView可直接调用JS方法

    WKWebView方法

    - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

    同样需要事先得知JS端的方法名和对应操作的key值 
    例如: 通知web某处理完成约定的 JS函数名为 function ,需要执行一个约定好的操作名为 action,则调用如下

    [self.webView evaluateJavaScript:@"function('action')" completionHandler:nil];

    七、同步标题

    有的时候 WKWebView所在UIViewController(视图控制器)是存在UINavigationController导航控制器的, 这时可能需要根据跳转的网页而变化标题,这时只需要KVO WKWebView 的 title 即可,并将最新的title赋值给 UIViewController 的 title 即可。

    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<nskeyvaluechangekey, id=""> *)change context:(nullable void *)context
    {
        if([keyPath isEqualToString:@"title"]){
            self.navigationItem.title = self.webView.title;
        }
    }</nskeyvaluechangekey,></wkscriptmessagehandler></nscoding></wkuidelegate></wknavigationdelegate></webkit>
  • 相关阅读:
    Ready!Api创建使用DataSource和DataSourceLoop的循环测试用例
    Tomcat8远程访问manager,host-manager被拒绝403
    银河军工:军工股数占证金公司买入比例最高
    操盘策略:如何追涨而不套牢
    老股民公开一个非常靠谱的炒股方法
    每日一招:调仓换股三大法宝
    每日一招:最高操作境界“一买就涨”
    每日一招:黄金做单时间
    每日一招:选股其实很简单
    操盘策略:只做大概率事件
  • 原文地址:https://www.cnblogs.com/m0m0/p/7726510.html
Copyright © 2020-2023  润新知