iOS下JS與OC互相調用(二)--WKWebView 攔截URL

在上篇文章中講述了使用UIWebView攔截URL的方式來處理JS與OC交互。 因爲UIWebView比較耗內存,性能上不太好,而蘋果在iOS 8中推出了WKWebView。 一樣的用WKWebView也能夠攔截URL,作JS 與OC交互。關於WKWebView與UIWebView的對比,你們請自動百度或者google。html

打開百度網頁前 打開百度網頁後
UIWebView 內存47M
WKWebView 內存47M

WKWebView 攔截URL

WKWebView 與 UIWebView 攔截URL 的處理方式基本同樣。除了代理方法和WKWebView的使用不太同樣,關於WKWebView更詳盡的講解和用法,仍是自行搜索學習,本文重點仍是講解如何實現JS 與OC 互相調用。java

提醒:WKWebView 是iOS 8 推出的WebKit.framework中的控件,只有app 不須要兼容iOS 7及如下的時候纔可使用。git

先看動態效果圖:github

1.建立WKWebView,加載本地HTML。

WKWebView的建立有幾點不一樣:web

  • 1.初始化多了個configuration參數,固然這個參數咱們也能夠不傳,直接使用默認的設置就好。
  • 2.WKWebView的代理有兩個navigationDelegateUIDelegate。咱們要攔截URL,就要經過navigationDelegate的一個代理方法來實現。若是在HTML中要使用alert等彈窗,就必須得實現UIDelegate的相應代理方法。
  • 3.在iOS 9以前,WKWebView加載本地HTML會有一些問題。(不能加載本地HTML,或者部分CSS/本地圖片加載不了等)

我這裏建立WKWebView的示例代碼是這樣的:bash

    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.frame configuration:configuration];
 
    NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
    NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
    [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
    
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
複製代碼

由於加載的本地HTML內容,跟上一篇UIWebView中介紹的HTML內容同樣,因此關於HTML中的內容就再也不講解了。app

2.攔截URL

使用WKNavigationDelegate中的代理方法,攔截自定義的URL來實現JS調用OC方法。ide

#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的狀況。學習

2.其餘的關於爲何要統一設置scheme,在上一篇中講過。

關於如何區分執行不一樣的OC 方法,也與UIWebView的處理方式同樣,經過URL 的host 來區分執行不一樣的方法:

#pragma mark - private method
- (void)handleCustomAction:(NSURL *)URL
{
    NSString *host = [URL host];
    if ([host isEqualToString:@"scanClick"]) {
        NSLog(@"掃一掃");
    } else if ([host isEqualToString:@"shareClick"]) {
        [self share:URL];
    } else if ([host isEqualToString:@"getLocation"]) {
        [self getLocation];
    } else if ([host isEqualToString:@"setColor"]) {
        [self changeBGColor:URL];
    } else if ([host isEqualToString:@"payAction"]) {
        [self payAction:URL];
    } else if ([host isEqualToString:@"shake"]) {
        [self shakeAction];
    } else if ([host isEqualToString:@"goBack"]) {
        [self goBack];
    }
}
複製代碼

3.OC 調用 JS 方法

JS 調用OC 方法後,有的操做可能須要將結果返回給JS。這時候就是OC 調用JS 方法的場景。 WKWebView 提供了一個新的方法evaluateJavaScript:completionHandler:,實現OC 調用JS 等場景。

- (void)getLocation
{
    // 獲取位置信息
    
    // 將結果返回給js
    NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省深圳市南山區學府路XXXX號"];
    [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 必定得調用,至於在哪裏調用,卻是無所謂,咱們也能夠寫在方法實現的第一行,或者最後一行。

示例工程地址:JS_OC_URL

相關文章
相關標籤/搜索