從UIWebView到WKWebView替換歷程(關(guān)于Js復(fù)雜交互)(二)

如果項(xiàng)目中沒(méi)有與復(fù)雜的Js交互,那么就不用經(jīng)歷下面這個(gè)相對(duì)復(fù)雜的探索過(guò)程了.

之前用webView與js交互

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    
    // 設(shè)置javaScriptContext上下文
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //將bsg對(duì)象指向自身//網(wǎng)頁(yè)端設(shè)置點(diǎn)擊方法:bsg.call()牧牢,call()方法由bsg對(duì)象調(diào)用,此處將自身設(shè)置為bsg對(duì)象,用來(lái)調(diào)用本地方法而非網(wǎng)頁(yè)方法
    self.jsContext[@"ios"] = self;
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"異常信息:%@", exceptionValue);
    };
}

想把webView替換成WKWebView梆掸,于是這樣寫:

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    
    // 設(shè)置javaScriptContext上下文
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    self.jsContext[@"ios"] = self;
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"異常信息:%@", exceptionValue);
    };
    
}

然后就崩潰了,在self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];這里崩了,原因就是WKWebView不支持JavaScriptCore的方式, 但提供messagehandler的方式為JavaScript與OC通信
到這里我們會(huì)想如何拿到WKWebView JsContext上下文,可是很遺憾
我們無(wú)法獲取上下文,因?yàn)椴季趾蚃avaScript是在另一個(gè)進(jìn)程上處理的。

相反,將腳本添加到您的webview配置中同木,并將視圖控制器(或另一個(gè)對(duì)象)設(shè)置為腳本消息處理器messageHandlers。

現(xiàn)在跛十,從JavaScript發(fā)送消息彤路,如下所示:

// js代碼
window.webkit.messageHandlers.interOp.postMessage(message)

您的腳本消息處理程序?qū)⑹盏揭粋€(gè)回調(diào):

// OC
- (void)userContentController:(WKUserContentController *)userContentController 
                            didReceiveScriptMessage:(WKScriptMessage *)message{
    NSLog(@"%@", message.body);
}

奇怪的是我們寫了代理方法也不會(huì)執(zhí)行,這是因?yàn)榻o我們?cè)瓉?lái)提供JS的前端代碼都是按UIWebView來(lái)寫的:

js示例

可以看出是這種形式,而不是WKWebView的postMessage這種形式,這就是問(wèn)題所在了.

當(dāng)你的項(xiàng)目需要從UIWebView換成WKWebView時(shí),或許會(huì)煩惱HTML那邊需要修改JS交互部分偶器,下面是解決方案斩萌,其實(shí)HTML并不需要修改任何代碼缝裤,而且iOS這邊改動(dòng)也非常簡(jiǎn)單屏轰。

首先假設(shè)HTML原本的JavaScript交互代碼如下

//JS代碼 - 1
if (window.jSBridgeInstance && window.jSBridgeInstance.sendMessage) {
    var act = "Action";
    var jsonDict = {
                      "imagUrl": "", 
                      "title": "積分商城", 
                      "login": "0"
                   };
    window.jSBridgeInstance.sendMessage(act, jsonDict);
}
如果要改HTML端的話,需要修改如下(但是我們不改HTML憋飞,我們改iOS端代碼)

//JS代碼 - 2
//如果修改HTML的JS代碼霎苗,則iOS不需要修改
if (window.webkit && window.webkit.messageHandlers) {
    var act = "Action";
    var jsonDict = {
                      "act" : act,
                      "imagUrl": "", 
                      "title": "積分商城", 
                      "login": "0"
                   };
    //注意,iOS的postMessage方法只接收一個(gè)參數(shù)榛做,如果傳多個(gè)參數(shù)唁盏,那么WKScriptMessage的body只接收到第一個(gè)參數(shù)
    window.webkit.messageHandlers.callTemplate.postMessage(jsonDict);
}
iOS 端修改如下(本篇文章的重點(diǎn))

OC代碼
//iOS 代碼 - 1
//如果修改iOS代碼,則JS代碼不需要修改
WKWebViewConfiguration *config = [WKWebViewConfiguration new];
[config.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"callTemplate"];
NSString *scriptSource = @"\
   window.jSBridgeInstance = window.webkit.messageHandlers.callTemplate;\
   window.jSBridgeInstance.sendMessage = function(act, json) {\
       var jsonDict = {\
           \"key1\": act,\
           \"key2\": json\
       };\
       window.webkit.messageHandlers.callTemplate.postMessage(jsonDict);\
   }";
WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:false];
[config.userContentController addUserScript:script];
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
Swift代碼
//iOS 代碼 - 2
//如果修改iOS代碼检眯,則JS代碼不需要修改
let config: WKWebViewConfiguration = WKWebViewConfiguration();
config.userContentController.add(WeakScriptMessageDelegate.initWith(self), name: "callTemplate");
let scriptSource: String = """
       window.jSBridgeInstance = window.webkit.messageHandlers.callTemplate;
       window.jSBridgeInstance.sendMessage = function(act, json) {
               var jsonDict = {
                   "key1": act,
                   "key2": json
               };
               window.webkit.messageHandlers.callTemplate.postMessage(jsonDict);
       }
 """;
let script:WKUserScript = WKUserScript.init(source: scriptSource, injectionTime: .atDocumentStart, forMainFrameOnly: false);
config.userContentController.addUserScript(script);
webView = WKWebView.init(frame: self.view.bounds, configuration: config);

注:
①第二行callTemplate可以隨意命名厘擂,假如你命名為x,那么對(duì)應(yīng)的scriptSource里邊的callTemplate也都修改為x锰瘸。
② scriptSource中jSBridgeInstance和sendMessage看你們的HTML的JS代碼而定刽严。
③如果原來(lái)的HTML的JS有三個(gè)參數(shù),那么修改如下:

NSString *scriptSource = @"\
   window.jSBridgeInstance = window.webkit.messageHandlers.callTemplate;\
   window.jSBridgeInstance.sendMessage = function(param1, param2, param3) {\
       var jsonDict = {\
           \"key1\": param1,\
           \"key2\": param2,\
           \"key3\": param3,\
       };\
       window.webkit.messageHandlers.callTemplate.postMessage(jsonDict);\
   }";

更多參數(shù)時(shí)以此類推避凝。

實(shí)踐:這里是window.SCAJSBridge.invoke所以是如下寫法
#pragma mark 獲取js上下文

- (void)getJsContext {
    //self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];//原來(lái)UIWebView獲取上下文的方式 WK無(wú)法沿用這種方式
// 新方法把self設(shè)置成ScriptMessageHandler
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"callTemplate"];
    NSString *scriptSource = @"\
    window.SCAJSBridge = window.webkit.messageHandlers.callTemplate;\
    window.SCAJSBridge.invoke = function(param1, param2, param3) {\
        var jsonDict = {\
            \"key1\": param1,\
            \"key2\": param2,\
            \"key3\": param3,\
        };\
        window.webkit.messageHandlers.callTemplate.postMessage(jsonDict);\
    }";
    WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:false];
    [self.webView.configuration.userContentController addUserScript:script];
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舞萄,一起剝皮案震驚了整個(gè)濱河市眨补,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倒脓,老刑警劉巖撑螺,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異崎弃,居然都是意外死亡甘晤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門饲做,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)安皱,“玉大人,你說(shuō)我怎么就攤上這事艇炎∽靡粒” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵缀踪,是天一觀的道長(zhǎng)居砖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)驴娃,這世上最難降的妖魔是什么奏候? 我笑而不...
    開(kāi)封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮唇敞,結(jié)果婚禮上蔗草,老公的妹妹穿的比我還像新娘。我一直安慰自己疆柔,他們只是感情好咒精,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著旷档,像睡著了一般模叙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞋屈,一...
    開(kāi)封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天范咨,我揣著相機(jī)與錄音,去河邊找鬼厂庇。 笑死渠啊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的权旷。 我是一名探鬼主播替蛉,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了灭返?” 一聲冷哼從身側(cè)響起盗迟,我...
    開(kāi)封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熙含,沒(méi)想到半個(gè)月后罚缕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怎静,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年邮弹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚓聘。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腌乡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夜牡,到底是詐尸還是另有隱情与纽,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布塘装,位于F島的核電站急迂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蹦肴。R本人自食惡果不足惜僚碎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阴幌。 院中可真熱鬧勺阐,春花似錦、人聲如沸矛双。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)背零。三九已至腰吟,卻和暖如春无埃,著一層夾襖步出監(jiān)牢的瞬間徙瓶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工嫉称, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侦镇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓织阅,卻偏偏與公主長(zhǎng)得像壳繁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359