苹果下发最后通牒,如果您的 app 仍在使用已弃用的 UIWebView API 嵌入网络内容,我们强烈建议您尽快更新为 WKWebView 以提升安全性和稳定性。WKWebView 可将网页处理限制在 app 的网页视图中,从而确保不安全的网站内容不会影响到 app 的其他部分。此外,iOS、macOSMac Catalyst 均支持 WKWebView

2020 年 4 月起 App Store 将不再接受使用 UIWebView 的新 app,2020 年 12 月起将不再接受使用 UIWebViewapp 更新。

虽然苹果声明 2020 年 12 月起将不再接受使用 UIWebViewapp 更新,但截止目前 2021年 11 月,苹果依然允许应用开发者更新基于 UIWebViewapp

关于iOS15

iOS15 正式版发布以来,发现在 iOS15 以下正常使用的桥接功能,在 iOS15 系统出现 H5 找不到桥接方法的问题,请尽快适配 WKWebView

前置条件

1、导入WebKit.framework
https://img.wangquanwei.com/wp-content/uploads/2018/12/7FEB3444-4B0D-4266-ABB9-87858B18BE6C.jpeg


2、声明WKWebView

@interface ViewController ()
@property (nonatomic, strong) WKWebView * webView;

@end

3、初始化

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    WKUserContentController *userController = [[WKUserContentController alloc] init];
    configuration.userContentController = userController;
    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kURL]];
    [self.webView loadRequest:request];
    [self.view addSubview:self.webView];
}


JS调用OC原生方法(无返回参数)

前端在js文件中实现

1、这里要注意 messageHandlers 后面跟着的 deviceInfo 要与原生的定义的一致,即 deviceInfoH5 与原生的桥接方法。
2、如有多个参数,请使用 json 形式传递。

//有参数
window.webkit.messageHandlers.deviceInfo.postMessage({
        "body": "buttonActionMessage"
});

//无参数
window.webkit.messageHandlers.deviceInfo.postMessage("");


iOS 实现 WKScriptMessageHandler 协议
@interface ViewController ()<WKScriptMessageHandler>
@property (nonatomic, strong) WKWebView * webView;

@end


注册桥接方法

注意:不要重复注册,否则会Crash

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


注销桥接方法
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"deviceInfo"];
}


iOS 实现 WKScriptMessageHandler 协议方法

message.body 就是前端传来的参数

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {

    if ([message.name isEqualToString:@"deviceInfo"]) {

        NSString *deviceInfoStr = message.body;
        NSLog(@"deviceInfo:%@", deviceInfoStr);

        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"JS调用的OC回调方法" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleCancel handler:nil];
        [alert addAction:action];
        [self presentViewController:alert animated:YES completion:nil];
    }

}


JS调用OC原生方法(有返回参数)

JS 调用 OC 原生方法后,需要原生处理完成后 return 个结果给 JS,例如: JS 获取原生用户信息

前端在js文件中实现

1、约定 text 参数为给原生桥接的方法名
2、约定 defaultText 参数为给原生的参数,如有多个,转成json字符串的形式传递

prompt(text, defaultText)
iOS 实现 WKUIDelegate 协议
@interface ViewController ()<WKUIDelegate, WKScriptMessageHandler>
@property (nonatomic, strong) WKWebView * webView;

@end


iOS 实现 WKUIDelegate 协议方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {

    if ([prompt isEqualToString:@"text"]) {
        // text 为约定好的桥接方法名
        // 如果需要返回前端对象,需要转成json字符串形式
        NSString * str = @"Hello world";
        completionHandler(str);
    }
}

OC调用JS方法

1、实现WKNavigationDelegate协议

@interface ViewController ()
@property (nonatomic, strong) WKWebView * webView;

@end



2、实现WKNavigationDelegate协议的- webView: didFinishNavigation:方法

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {

}



3、OC调用JS方法

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {

    [webView evaluateJavaScript:@"deviceInfo('8.3')" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"ok");
    }];

}

其中 deviceInfo(‘8.3’) 为前端给出的 JS 方法名 8.3 是需要传给前端的参数,如果需要传递多个参数,请使用 json 字符串。

4、注意事项

以下错误的解决方法

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

一定要在网页加载完成后调用,否则报错

JS方法一定要放在最外层

图片出处不详,请作者看到与我联系,侵删