WKWebView 与 JS 交互的特有方法

WKWebView 在与 JS 的交互时特有的方法:

WKUIDelegate 方法
MessageHandler 方法

  1. WKUIDelegate 方法

WKUIDelegate 协议包含一些函数用来监听 web JS 想要显示 alert 或 confirm 时触发。我们如果在 WKWebView 中加载一个 web 并且想要 web JS 的 alert 或 confirm 正常弹出,就需要实现对应的代理方法。( 如果没有实现对应的代理方法,则 webview 将会按照默认操作去做出行为。)

下面是在 WKUIDelegate 监听 web 要显示 alert 的代理方法中用 Native UIAlertController 替代 JS 中的 alert 显示的例子 :

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    // 用 Native 的 UIAlertController 弹窗显示 JS 将要提示的信息
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒"     message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了"     style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        // 函数内必须调用 completionHandler
        completionHandler();
    }]];

    [self presentViewController:alert animated:YES completion:nil];
}
  1. MessageHandler 方法

MessageHandler 是继 Native 截获 JS 假请求后另一种 JS 调用 Native 的方法,该方法利用了 WKWebView 的新特性实现。对比截获假 Request 的方法来说,MessageHandler 传参数相对简单方便。

MessageHandler 指什么?

WKUserContentController 类有一个方法:

- (void)addScriptMessageHandler:(id )scriptMessageHandler name:(NSString *)name;

该方法用来添加一个脚本处理器,可以在处理器内对 JS 脚本调用的方法做出处理,从而达到 JS 调用 Native 的目的。

那么 WKUserContentController 类和 WKWebView 有什么关系呢?

在 WKWebView 的初始化函数中有一个入参 configuration,它的类型是 WKWebViewConfiguration。WKWebViewConfiguration 中包含一个属性 userContentController,这个 userContentController 就是 WKUserContentController 类型的实例,我们可以用这个 userContentController 来添加不同名称的脚本处理器。

2.1. MessageHandler 的坑

回到 - (void)addScriptMessageHandler:name: 方法上面,该方法添加一个脚本消息处理器(第一个入参 scriptMessageHandler),并且给这个处理器起一个名字(第二个入参 name)。不过这个函数在使用的时候有个坑:scriptMessageHandler 入参会被强引用,那么如果你把当前 WKWebView 所在的 UIViewController 作为第一个入参,这个 viewController 被他自己所持有的 webview.configuration. userContentController 所持有,就会造成循环引用。

640.jpg

我们可以通过 - (void)removeScriptMessageHandlerForName: 方法删掉 userContentController 对 viewController 的强引用。所以一般情况下我们的代码会在 viewWillAppear 和 viewWillDisappear 成对儿的添加和删除 MessageHandler:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.webview.configuration.userContentController addScriptMessageHandler:self name:@"YourFuncName"];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.webview.configuration.userContentController removeScriptMessageHandlerForName:@"YourFuncName"];
}

WKScriptMessageHandler 协议

WKScriptMessageHandler 是脚本信息处理器协议,如果想让一个对象具有脚本信息处理能力就必须使其遵循该协议。

WKScriptMessageHandler 协议内部非常简单,只有一个方法,我们必须要实现该方法(@required):

// WKScriptMessageHandler 协议方法,在接收到脚本信息时触发
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    // message 有两个属性:name 和 body
    // message.name 可以用于区别要做的处理
    if ([message.name isEqualToString:@"YourFuncName"]) {
        // message.body 相当于 JS 传递过来的参数
        NSLog(@"JS call native success %@", message.body);
    }
}

补充 JS 的代码:

//  换 YourFuncName, 换你要的入参即可
window.webkit.messageHandlers..postMessage()

你可能感兴趣的:(WKWebView 与 JS 交互的特有方法)