iOS下JS與OC互相調(diào)用(四)-MessageHandler

序言

使用WKWebView的時(shí)候,如果想要實(shí)現(xiàn)JS調(diào)用OC方法,除了攔截URL之外,還有一種簡(jiǎn)單的方式。那就是利用WKWebView的新特性MessageHandler來(lái)實(shí)現(xiàn)JS調(diào)用原生方法。

一. MessageHandler 是什么?

WKWebView初始化時(shí),有一個(gè)參數(shù)叫configuration,它是WKWebViewConfiguration類型的參數(shù),而WKWebViewConfiguration有一個(gè)屬性叫WKWebViewConfiguration,它是WKUserContentController類型的參數(shù)。WKUserContentController對(duì)象有一個(gè)方法- addScriptMessageHandler:name:,這個(gè)功能就簡(jiǎn)稱MessageHandler

- addScriptMessageHandler:name:有兩個(gè)參數(shù),第一個(gè)參數(shù)是userContentController的代理對(duì)象,第二個(gè)參數(shù)是JS里發(fā)送postMessage的對(duì)象。
所以要使用MessageHandler功能,就必須要實(shí)現(xiàn)WKScriptMessageHandler協(xié)議。

二. 怎么使用MessageHandler?
2.1 創(chuàng)建WKWebViewConfiguration對(duì)象,配置各個(gè)API對(duì)應(yīng)的MessageHandler。

WKUserContentController對(duì)象可以添加多個(gè)scriptMessageHandler。

示例代碼如下
初始化WKWebViewConfiguration和WKWebView

- (void)drawUI {
    // WKWebViewConfiguration
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    WKPreferences *preference = [WKPreferences new];
    preference.javaScriptCanOpenWindowsAutomatically = YES;
    preference.minimumFontSize = 40.0;
    configuration.preferences = preference;
    
    // WKWebView
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds 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.webView.UIDelegate = self;
    [self.view addSubview:self.webView];
}

然后在界面即將顯示的時(shí)候添加MessageHandler

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    // addScriptMessageHandler 很容易導(dǎo)致循環(huán)引用
    // 控制器 強(qiáng)引用了WKWebView,WKWebView copy(強(qiáng)引用了)configuration, configuration copy (強(qiáng)引用了)userContentController
    // userContentController 強(qiáng)引用了 self (控制器)
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"ScanAction"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Location"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Color"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Pay"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Shake"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"GoBack"];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"PlaySound"];
}

需要注意的是addScriptMessageHandler很容易引起循環(huán)引用,導(dǎo)致控制器無(wú)法被釋放,所以需要移除MessageHandler

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    // 因此這里要記得移除handlers
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"ScanAction"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Location"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Share"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Color"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Pay"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Shake"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"GoBack"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"PlaySound"];
}
2.2 實(shí)現(xiàn)協(xié)議方法

這里實(shí)現(xiàn)了兩個(gè)協(xié)議<WKUIDelegate,WKScriptMessageHandler>,WKUIDelegate是因?yàn)槲以贘S中彈出了alert 。WKScriptMessageHandler是因?yàn)槲覀円幚鞪S調(diào)用OC方法的請(qǐng)求。
示例代碼如下

#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    // message.body  --  Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
    if ([message.name isEqualToString:@"ScanAction"]) {
        [self scanAction];
    } else if ([message.name isEqualToString:@"Location"]) {
        [self getLocation];
    } else if ([message.name isEqualToString:@"Share"]) {
        [self shareWithParams:message.body];
    } else if ([message.name isEqualToString:@"Color"]) {
        [self changeBGColor:message.body];
    }else if ([message.name isEqualToString:@"GoBack"]) {
        [self goBack];
    }
}

WKScriptMessage有兩個(gè)關(guān)鍵屬性namebody。
因?yàn)槲覀兘o每一個(gè)OC 方法取了一個(gè)name,那么我們就可以根據(jù)name 來(lái)區(qū)分執(zhí)行不同的方法。body 中存著JS 要給OC 傳的參數(shù)。

關(guān)于參數(shù)body 的解析,我就舉一個(gè)body中放字典的例子,其他的稍后可以看demo。
解析JS 調(diào)用OC 實(shí)現(xiàn)分享的參數(shù):

- (void)shareWithParams:(NSDictionary *)params {
    if (![params isKindOfClass:[NSDictionary class]]) {
        return;
    }
    NSString *title = [params objectForKey:@"title"];
    NSString *content = [params objectForKey:@"content"];
    NSString *url = [params objectForKey:@"url"];
    
    // 在這里執(zhí)行分享的操作
    NSLog(@"在這里執(zhí)行分享的操作");
    
    // 將分享結(jié)果返回給js
    NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id result, NSError *error) {
        NSLog(@"%@----%@",result, error);
    }];
}

message.boby 就是JS 里傳過(guò)來(lái)的參數(shù)。我們不同的方法先做一下容錯(cuò)性判斷。然后正常取值就可以了。

2.3 處理HTML中JS調(diào)用

下面只列舉一個(gè)shareClick()方法,其他看Demo

// 傳字典              
function shareClick(){
  window.webkit.messageHandlers.Share.postMessage({title:'測(cè)試分享的標(biāo)題',content:'測(cè)試分享的內(nèi)容',url:'http://www.baidu.com'});
}

function shareResult(channel_id,share_channel,share_url) {
    var content = channel_id+","+share_channel+","+share_url;
    asyncAlert(content);
    document.getElementById("returnValue").value = content;
}
            
function asyncAlert(content) {
    setTimeout(function(){
        alert(content);
    },1);
}
2.4 OC調(diào)用JS

這里使用WKWebView 實(shí)現(xiàn)OC 調(diào)用JS方法與之前說(shuō)的文章一樣,通過(guò)- evaluateJavaScript:completionHandler:
示例代碼如下:

// 將分享結(jié)果返回給js
NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    NSLog(@"%@----%@",result, error);
}];
三. 使用MessageHandler的好處
  • 1.在JS中寫(xiě)起來(lái)簡(jiǎn)單,不用再用創(chuàng)建URL的方式那么麻煩了。
  • 2.JS傳遞參數(shù)更方便。使用攔截URL的方式傳遞參數(shù),只能把參數(shù)拼接在后面,如果遇到要傳遞的參數(shù)中有特殊字符,如&、=、?等,必須得轉(zhuǎn)換,否則參數(shù)解析肯定會(huì)出錯(cuò)。

效果圖如下圖所示

JS_OC_WK_MessageHandler.gif

項(xiàng)目連接地址


本文參考iOS下JS與OC互相調(diào)用(三)--MessageHandler,非常感謝該作者。


更多 JS 與 OC 交互文章請(qǐng)看下面
iOS下 JS 與OC 互相調(diào)用(一) - UIWebView 攔截 URL
iOS下 JS 與OC 互相調(diào)用(二) - JavaScriptCore
iOS 下 JS 與 OC 互相調(diào)用(三) - WKWebView 攔截 URL
iOS下 JS 與 OC 互相調(diào)用(五) - UIWebView+WebViewJavascriptBridge
iOS下 JS 與 OC 互相調(diào)用(六) - WKWebView+WKWebViewJavascriptBridge

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 使用WKWebView的時(shí)候,如果想要實(shí)現(xiàn)JS調(diào)用OC方法,除了攔截URL之外,還有一種簡(jiǎn)單的方式。那就是利用WK...
    咖啡綠茶1991閱讀 1,158評(píng)論 0 1
  • 種簡(jiǎn)單的方式。那就是利用WKWebView的新特性MessageHandler來(lái)實(shí)現(xiàn)JS調(diào)用原生方法。 Messa...
    水靈芳蕥閱讀 1,495評(píng)論 0 1
  • 前言 Web 頁(yè)面中的 JS 與 iOS Native 如何交互是每個(gè) iOS 猿必須掌握的技能。而說(shuō)到 Nati...
    幽城88閱讀 2,327評(píng)論 1 8
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,632評(píng)論 1 32
  • “仲夏之夜,游離的思緒伴隨著悠長(zhǎng)的黑夜莫名的恐慌起來(lái)。拉開(kāi)窗簾,我希望有縷光芒透過(guò)窗戶,甚至我的內(nèi)心,掃走我的孤寂...
    Archer_015閱讀 303評(píng)論 0 2

友情鏈接更多精彩內(nèi)容