iOS下JS与OC互相调用

iOS 下 JS 与 OC 互相调用(三) - WKWebVie

2018-08-04  本文已影响154人  路飞_Luck

序言

之前有文章介绍使用 UIWebView 拦截 URL 的方式来处理 JS 与 OC 交互。iOS 下 JS 与原生 OC 互相调用(总结),但是由于UIWebVIew 比较耗内存,性能上不太好。并且苹果在 iOS 8中推出了WKWebView。所以同样可以使用WKWebView 来拦截 URL,做 JS 与 OC 的交互。

提醒:WKWebView 是iOS 8 推出的WebKit.framework中的控件,只有app 不需要兼容iOS 7及以下的时候才可以使用。

先看看动态效果图

JS_OC_WK_URL.gif

1.创建 WKWebView,加载本地 HTML 文件

WKWebView的创建有几点不同:

创建WKWebView的示例代码如下:

- (void)initWKWebView {
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = [WKUserContentController new];
    
    WKPreferences *preferences = [WKPreferences new];
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    preferences.minimumFontSize = 30.0;
    configuration.preferences = preferences;
    
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
    
    // load
    NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:@""];
    NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
    [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
    
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
}

加载本地HTML 内容,之前有讲解过,感兴趣的读者可以看看上面的连接,这里不再过多的介绍。

2.拦截 URL

使用WKNavigationDelegate中的代理方法,拦截自定义的 URL 来实现 JS 调用 OC 方法。

#pragma mark - WKNavigationDelegate

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURL *URL = navigationAction.request.URL;
    NSString *scheme = [URL scheme];
    if ([scheme isEqualToString:@"haleyaction"]) {
        [self handleCustomAction:URL];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

需要注意的是

1.如果实现了这个代理方法,就必须得调用decisionHandler这个 block,否则会导致 app 奔溃。block 参数是一个枚举值,WKNavigationActionPolicyCancel代表取消加载,相当于UIWebView的代理方法return NO的情况;WKNavigationActionPolicyAllow代表允许加载,相当于UIWebView的代理方法中 return YES的情况。

关于如何区分执行不同的OC 方法,也与UIWebView的处理方式一样,通过URL 的host 来区分执行不同的方法:

#pragma mark - dealwith custom action

- (void)handleCustomAction:(NSURL *)URL {
    NSString *host = [URL host];
    
    if ([host isEqualToString:@"shareClick"]) {
        [self share:URL];
    } else if ([host isEqualToString:@"getLocation"]) {
        [self getLocation:URL];
    } else if ([host isEqualToString:@"setBGColor"]) {
        [self setBGColor:URL];
    } else if ([host isEqualToString:@"payAction"]) {
        [self payAction:URL];
    } else if ([host isEqualToString:@"shake"]) {
        [self shakeAction];
    } else if ([host isEqualToString:@"back"]) {
        [self goBack];
    }
}

3.OC 调用 JS 方法

JS 调用OC 方法后,有的操作可能需要将结果返回给JS。这时候就是OC 调用JS 方法的场景。
WKWebView 提供了一个新的方法evaluateJavaScript:completionHandler:,实现OC 调用JS 等场景。

- (void)getLocation:(NSURL *)URL {
    // 获取位置信息
    NSLog(@"原生获取位置信息操作");
    
    // 将结果返回给 JS
    NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省广州市白云区豪泉大厦"];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];
}

evaluateJavaScript:completionHandler:没有返回值,JS 执行成功还是失败会在completionHandler 中返回。所以使用这个API 就可以避免执行耗时的JS,或者alert 导致界面卡住的问题。

4.WKWebView 中使用弹窗

在上面提到,如果在WKWebView中使用alert、confirm 等弹窗,就得实现WKWebView的WKUIDelegate中相应的代理方法。
例如,我在JS中要显示alert 弹窗,就必须实现如下代理方法,否则alert 并不会弹出。

#pragma mark - WKUIDelegate

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    
    [self presentViewController:alert animated:YES completion:nil];
}

其中completionHandler这个block 一定得调用,至于在哪里调用,倒是无所谓,我们也可以写在方法实现的第一行,或者最后一行。


本文参考iOS下JS与OC互相调用(二)--WKWebView 拦截URL,非常感谢该作者。


项目连接地址


更多 JS 与 OC 交互文章请看下面
iOS下 JS 与OC 互相调用(一) - UIWebView 拦截 URL
iOS下 JS 与OC 互相调用(二) - JavaScriptCore
iOS下JS与OC互相调用(四)-MessageHandler
iOS下 JS 与 OC 互相调用(五) - UIWebView+WebViewJavascriptBridge
iOS下 JS 与 OC 互相调用(六) - WKWebView+WKWebViewJavascriptBridge

上一篇下一篇

猜你喜欢

热点阅读