iOS常用方法——WKWebView与h5交互的实现

随着前端开发的强大,原生与h5的交互用的也越来越多。
为什么选用WKWebView,我们可以做一个对比,同一个web页面,用UIWebView加载和用WKWebView来加载,内存占用情况很容易看出来,回到原生页面之后,UIWebView对应的内存也不会降下来。从性能而言,个人觉得能用WKWebView就不要用UIWebView。
UIWebView与h5的交互方式和WKWebView与h5的交互方式不太一样,对h5那边的实现方式要求也不一样。下面给一个WKWebView与h5实现交互的主要代码。

  • 需要的成员变量的初始化:
//初始化webView
-(WKWebView *)webView{
    if (!_webView) {
        _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - self.mNavigationbarHeight) configuration:self.configuration];
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
    }
    return _webView;
}

//初始化配置
-(WKWebViewConfiguration *)configuration{
    if (!_configuration) {
        _configuration = [[WKWebViewConfiguration alloc] init];
        WKPreferences *preferences = [WKPreferences new];
        preferences.javaScriptCanOpenWindowsAutomatically = YES;
        _configuration.preferences = preferences;
        _configuration.userContentController = self.userContentController;
    }
    return _configuration;
}

-(WKUserContentController *)userContentController{
    if (!_userContentController) {
        _userContentController = [[WKUserContentController alloc] init];
        //交互关键代码
        [_userContentController addScriptMessageHandler:self name:@"webViewApp"];
    }
    return _userContentController;
}
  • WKWebView相关代理及交互的实现
#pragma mark - WKUIDelegate
// 在JS端调用alert函数时,会触发此代理方法。
// JS端调用alert时所传的数据可以通过message拿到
// 在原生得到结果后,需要回调JS,是通过completionHandler回调
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];

    [self presentViewController:alert animated:YES completion:NULL];
    NSLog(@"%@", message);
}

// JS端调用confirm函数时,会触发此方法
// 通过message可以拿到JS端所传的数据
// 在iOS端显示原生alert得到YES/NO后
// 通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%s", __FUNCTION__);

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:NULL];

    NSLog(@"%@", message);
}

// JS端调用prompt函数时,会触发此方法
// 要求输入一段文本
// 在原生输入得到文本内容后,通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    NSLog(@"%s", __FUNCTION__);

    NSLog(@"%@", prompt);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"请输入" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.textColor = [UIColor redColor];
    }];

    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler([[alert.textFields lastObject] text]);
    }]];

    [self presentViewController:alert animated:YES completion:NULL];
}
#pragma mark - WKNavigationDelegate
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    //页面开始加载

}

-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    //内容开始到达时
}

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    //页面加载完成

}

-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    //页面加载失败

}

-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
    //收到服务器重定向请求后调用
}

-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    // 在请求开始加载之前调用,决定是否跳转
    decisionHandler(WKNavigationActionPolicyAllow);
}

-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    // 在收到响应开始加载后,决定是否跳转
    decisionHandler(WKNavigationResponsePolicyAllow);
}

#pragma mark - WKScriptMessageHandler
//实现交互的代理
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    //message.body为h5向原生交互时所传的参数,这个为客户端与h5端协商,端需要什么就让h5端给什么
    NSDictionary * messageDic = message.body;
    //以下为协商后处理的一个实例,根据方法名判断原生需要做什么处理
    if ([messageDic[@"method"] isEqualToString:@"h5share"]) {
        //调起原生分享页面
        [BZJSInteractiveManager h5shareInteractive:messageDic];
    }else if ([messageDic[@"method"] isEqualToString:@"mall_wxpay"]){
        //微信支付
        [BZJSInteractiveManager h5WeiXinPayInteractive:messageDic[@"result"][@"payuri"]];
    }else if ([messageDic[@"method"] isEqualToString:@"h5tologin"]){
        //token失效
        [BZJSInteractiveManager h5ToLogin];
    }
}

需要注意的一点是WKUIDelegate需要按上面的代码处理,否则h5中的一些弹框无法弹出。
如果项目中用到的web比较多,可以写一个基类,基类中基本可以实现大部分功能,交互的处理也可以在基类中统一分发处理,这样的话交互不必在意是哪个界面,只要确定交互方法,在任何页面有交互都可以实现。
h5实现交互代码示例:

  • 按钮:
<p align="center"> <input type="button" value="测试WKWebView中..." onClick="functest1()"></p>
  • 点击方法:
function functest1(){
    var message = {
    'method' : 'hello',
    'param1' : 'liuyanwei',
    };
    //这句为关键代码,没有这句,客户端无法再代理方法中获取到该点击事件
    window.webkit.messageHandlers.webViewApp.postMessage(message);
}

代码地址:https://download.csdn.net/download/aaaaazq/10516539
该代码中包含了一个完整的使用WKWebView的基类,功能比较完整。

猜你喜欢

转载自blog.csdn.net/aaaaazq/article/details/80899645