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中寫起來(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)系作者
  • 序言:七十年代末尼斧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子试吁,更是在濱河造成了極大的恐慌棺棵,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熄捍,死亡現(xiàn)場(chǎng)離奇詭異烛恤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)余耽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門缚柏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人碟贾,你說(shuō)我怎么就攤上這事币喧。” “怎么了袱耽?”我有些...
    開(kāi)封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵杀餐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我朱巨,道長(zhǎng)史翘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮琼讽,結(jié)果婚禮上必峰,老公的妹妹穿的比我還像新娘。我一直安慰自己钻蹬,他們只是感情好自点,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著脉让,像睡著了一般。 火紅的嫁衣襯著肌膚如雪功炮。 梳的紋絲不亂的頭發(fā)上溅潜,一...
    開(kāi)封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音薪伏,去河邊找鬼滚澜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嫁怀,可吹牛的內(nèi)容都是我干的设捐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼塘淑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萝招!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起存捺,我...
    開(kāi)封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤槐沼,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后捌治,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岗钩,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年肖油,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兼吓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡森枪,死狀恐怖视搏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疲恢,我是刑警寧澤凶朗,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站显拳,受9級(jí)特大地震影響棚愤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一宛畦、第九天 我趴在偏房一處隱蔽的房頂上張望瘸洛。 院中可真熱鬧,春花似錦次和、人聲如沸反肋。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)石蔗。三九已至,卻和暖如春畅形,著一層夾襖步出監(jiān)牢的瞬間养距,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工日熬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棍厌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓竖席,卻偏偏與公主長(zhǎng)得像耘纱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毕荐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

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