關(guān)于js和swift交互的理解(二)

本來打算第二天就寫呢辜纲,結(jié)果一直忙到了周五笨觅,想想怕忘了寫拦耐,于是擠了一點(diǎn)時(shí)間來把剩下的給大家補(bǔ)上,上篇文章介紹的swift調(diào)用js(文章地址?)见剩,這篇文章介紹js調(diào)用swift

1.JS調(diào)用OC:webView攔截鏈接的方法

此方法本人并沒有測(cè)試杀糯,是直接copy過來的,因?yàn)楦杏X此方法不是很好

-(BOOL)webView:(UIWebView *)webView

shouldStartLoadWithRequest:(NSURLRequest *)request

navigationType:(UIWebViewNavigationType)navigationType;

實(shí)現(xiàn)以上webView的代理方法苍苞,當(dāng)webView每次開始加載URL時(shí)會(huì)進(jìn)入這個(gè)方法固翰,我們便可以在這個(gè)方法實(shí)現(xiàn)JS調(diào)用OC。

JS代碼如下:

OC代碼如下:

如上圖當(dāng)JS中window.location.href = "iOS:shareToTest"的代碼被觸發(fā)柒啤,會(huì)進(jìn)入OC中的這個(gè)代理方法倦挂,并且獲得"iOS:shareToTest"這個(gè)字符串,接下進(jìn)行一系列的字符串解釋担巩,得到需要被實(shí)現(xiàn)的方法名且調(diào)用方援。如果需要傳值可把需要傳的值拼接在字符串上,字符串解釋后獲取響應(yīng)的值后調(diào)用一下方法:

這種JS調(diào)用OC的方法的缺點(diǎn)十分明顯涛癌,需要繁瑣地解釋字符串得到相應(yīng)的方法名和傳值犯戏,且最多只能有兩個(gè)值,調(diào)用的方法也不能傳遞返回值拳话;但是也有一個(gè)優(yōu)點(diǎn):不需要等待頁面加載完才觸發(fā)先匪,當(dāng)相應(yīng)的代碼被運(yùn)行就能調(diào)用OC的方法,這也是下面要講到的JavaScriptCore的一個(gè)小坑弃衍。

2.蘋果推薦的框架--JavaScriptCore

這種方法是利用iOS7后新出的框架實(shí)現(xiàn)的呀非,跟我上文swift調(diào)用js 第二個(gè)方法是配套使用的,下面上代碼:

首先創(chuàng)建一個(gè)類JSObjCModel和JavaScriptSwiftDelegate镜盯,代理里面寫的是js可以調(diào)用的方法岸裙,JSObjCModel這個(gè)名字需要跟前端的小伙伴一起約定好的,js里面也是要用的

import UIKit

import JavaScriptCore

// All methods that should apply in Javascript, should be in the following protocol.

@objc protocol JavaScriptSwiftDelegate: JSExport {

func callSystemCamera();

func showAlert(_ title: String, msg: String);

func callWithDict(_ dict: [String: AnyObject])

func jsCallObjcAndObjcCallJsWithDict(_ dict: [String: AnyObject]);

}

class JSObjCModel: NSObject,JavaScriptSwiftDelegate {

weak var controller: UIViewController?

weak var jsContext: JSContext?

func goGroup(_ commonId: String) {

print(commonId)

}

func callSystemCamera() {

print("js call objc method: callSystemCamera");

let jsFunc = self.jsContext?.objectForKeyedSubscript("jsFunc");

print(jsFunc?.toString()!)

jsFunc?.call(withArguments: []);

}

func showAlert(_ title: String, msg: String) {

DispatchQueue.main.async { () -> Void in

let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)

alert.addAction(UIAlertAction(title: "ok", style: .default, handler: nil))

self.controller?.present(alert, animated: true, completion: nil)

}

}

// JS調(diào)用了我們的方法

func callWithDict(_ dict: [String : AnyObject]) {

print("js call objc method: callWithDict, args: %@", dict)

}

// JS調(diào)用了我們的就去

func jsCallObjcAndObjcCallJsWithDict(_ dict: [String : AnyObject]) {

print("js call objc method: jsCallObjcAndObjcCallJsWithDict, args: %@", dict)

let jsParamFunc = self.jsContext?.objectForKeyedSubscript("jsParamFunc");

let dict = NSDictionary(dictionary: ["age": 18, "height": 168, "name": "lili"])

jsParamFunc?.call(withArguments: [dict])

}

}

然后就需要在webViewDidFinishLoad把剛剛創(chuàng)建的那個(gè)類注入到j(luò)s里面速缆,那么js就可以通過這個(gè)類去調(diào)用swift里的方法了

func webViewDidFinishLoad(_ webView: UIWebView) {

hideActivity()

//刪除頭部試圖

let header = "document.getElementById('header').remove()"

webView.stringByEvaluatingJavaScript(from: header)

self.title = webView.stringByEvaluatingJavaScript(from: "document.title")

let context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext

let model = JSObjCModel()

model.controller = self

model.jsContext = context

self.jsContext = context

// 這一步是將OCModel這個(gè)模型注入到JS中降允,在JS就可以通過OCModel調(diào)用我們公暴露的方法了。

self.jsContext?.setObject(model, forKeyedSubscript: "OCModel" as (NSCopying & NSObjectProtocol)!)

self.jsContext?.exceptionHandler = {

(context, exception) in

print("exception @", exception!)

}

}

第三部js里面的寫法是(如圖艺糜,奇怪的是為何不能復(fù)制了剧董,直接截圖了),這個(gè)OCModel必須跟你的小伙伴商量好才可以破停,注意你在webViewDidFinishLoad里注入模型的時(shí)候?qū)懙谋仨氁恢虏判?/p>



但是注意這個(gè)框架最需要強(qiáng)調(diào)的一點(diǎn)是:JS調(diào)用OC時(shí)翅楼,是需要等瀏覽器加載完頁面后才能進(jìn)行交互(相當(dāng)坑、很坑U媛R汶!)晤碘,這個(gè)是需要看需求的褂微,如果你需要在網(wǎng)頁加載的時(shí)候就調(diào)用功蜓,就放棄這個(gè)方吧,繼續(xù)看下面的第三種辦法

這個(gè)方法邊寫邊發(fā)現(xiàn)了問題宠蚂,問題如下調(diào)用2個(gè)參數(shù)時(shí)式撼,怎么調(diào)用都不成功,如下圖所有的地方都沒錯(cuò):



而js里的調(diào)用方法就是寫的


大概經(jīng)過半天的測(cè)試和調(diào)試求厕,我終于發(fā)現(xiàn)了問題所在:

這就是咱們基礎(chǔ)知識(shí)不扎實(shí)的地方了著隆,還記得swift里的方法名是怎么定義的嗎?呀癣?美浦?

js里的方法應(yīng)該寫成什么就對(duì)了呢?

經(jīng)過本大神的認(rèn)真審查js里應(yīng)該這么寫navigateToCreateGroupBuyDataString才可以調(diào)到swift的方法项栏,怎么樣是不是想起了什么

3.優(yōu)秀的第三方框架--WebViewJavascriptBridge

由于我利用第二個(gè)就解決了需求浦辨,但是我還是感覺第三種方法最好,目前這個(gè)庫還在更新中沼沈,我也沒有用我的swift項(xiàng)目中流酬,但是目測(cè)這是最好的解決方法,寫到這里我還是忍不住列另,相對(duì)它嘗試一下

先奉上這個(gè)框架的GitHub地址WebViewJavascriptBridge

具體用法在GitHub上說的挺詳細(xì)的芽腾,下面大概說一下吧:

1) 首先把第三方加入你的項(xiàng)目并引用文件

#import"WebViewJavascriptBridge.h"

...

@property WebViewJavascriptBridge* bridge;

2) 注冊(cè)一個(gè)WebViewJavascriptBridge的對(duì)象 可以用 WKWebView, UIWebView (iOS) or WebView (OSX):

self.bridge = [WebViewJavascriptBridgebridgeForWebView:webView];

3) oc里面注冊(cè)一個(gè)Handler和發(fā)送一個(gè)call(圖解)

handler注冊(cè)

[self.bridgeregisterHandler:@"ObjC Echo"handler:^(iddata, WVJBResponseCallback responseCallback) {NSLog(@"ObjC Echo called with:%@", data);responseCallback(data);}];

發(fā)送call

[self.bridgecallHandler:@"JS Echo"data:nilresponseCallback:^(idresponseData) {NSLog(@"ObjC received response:%@", responseData);}];


4) 把下述代碼復(fù)制到JS

functionsetupWebViewJavascriptBridge(callback) {if(window.WebViewJavascriptBridge) {returncallback(WebViewJavascriptBridge); }if(window.WVJBCallbacks) {returnwindow.WVJBCallbacks.push(callback); }window.WVJBCallbacks=[callback];varWVJBIframe=document.createElement('iframe');WVJBIframe.style.display='none';WVJBIframe.src='https://__bridge_loaded__';document.documentElement.appendChild(WVJBIframe);setTimeout(function() {document.documentElement.removeChild(WVJBIframe) },0)}


5)js里面寫的方法

setupWebViewJavascriptBridge(function(bridge) {/*Initialize your app here*/bridge.registerHandler('JS Echo',function(data,responseCallback) {console.log("JS Echo called with:", data)responseCallback(data)? ? })bridge.callHandler('ObjC Echo', {'key':'value'},functionresponseCallback(responseData) {console.log("JS received response:", responseData)? ? })})

如果真的要用到這個(gè)框架,除了iOS的開發(fā)人員外页衙,也要讓后臺(tái)的人了解這個(gè)框架摊滔,并在合適的位置注入上述JS代碼,雖然是比較麻煩店乐,但是這個(gè)框架確實(shí)挺好用艰躺,推薦指數(shù)5顆星!O斐病描滔!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棒妨,一起剝皮案震驚了整個(gè)濱河市踪古,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌券腔,老刑警劉巖伏穆,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異纷纫,居然都是意外死亡枕扫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門辱魁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烟瞧,“玉大人诗鸭,你說我怎么就攤上這事〔蔚危” “怎么了强岸?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)砾赔。 經(jīng)常有香客問我蝌箍,道長(zhǎng),這世上最難降的妖魔是什么暴心? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任妓盲,我火速辦了婚禮,結(jié)果婚禮上专普,老公的妹妹穿的比我還像新娘悯衬。我一直安慰自己,他們只是感情好檀夹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布甚亭。 她就那樣靜靜地躺著,像睡著了一般击胜。 火紅的嫁衣襯著肌膚如雪亏狰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天偶摔,我揣著相機(jī)與錄音暇唾,去河邊找鬼。 笑死辰斋,一個(gè)胖子當(dāng)著我的面吹牛策州,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宫仗,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼够挂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了藕夫?” 一聲冷哼從身側(cè)響起孽糖,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毅贮,沒想到半個(gè)月后办悟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滩褥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年病蛉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铺然,死狀恐怖俗孝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情魄健,我是刑警寧澤驹针,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站诀艰,受9級(jí)特大地震影響柬甥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜其垄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一苛蒲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绿满,春花似錦臂外、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至橘霎,卻和暖如春蔫浆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姐叁。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工瓦盛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人外潜。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓原环,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親处窥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱吗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • 隨著H5技術(shù)的興起,在iOS開發(fā)過程中滔驾,難免會(huì)遇到原生應(yīng)用需要和H5頁面交互的問題谒麦。其中會(huì)涉及方法調(diào)用及參數(shù)傳值等...
    Chris_js閱讀 3,060評(píng)論 1 8
  • 最近整理了一下原生與H5之間的交互方式,簡(jiǎn)單的做個(gè)總結(jié)嵌灰。OC端與JS的交互弄匕,大致有這幾種:攔截協(xié)議颅悉、JavaScr...
    談Xx閱讀 31,102評(píng)論 41 75
  • 進(jìn)入15年以后沽瞭,在我們天朝越來越流行混編!尤其是騰訊的 變態(tài)APP微信小程序一出剩瓶,撐起了混編的半邊天驹溃! 廢話不多說...
    白水灬煮一切閱讀 1,224評(píng)論 0 2
  • 最近在做的項(xiàng)目重點(diǎn)就是原生app與js的交互城丧,以前也做過但是并沒有深入的了解和研究過,因?yàn)檫@個(gè)項(xiàng)目我嘗試了三種方式...
    Www劉閱讀 14,210評(píng)論 3 53
  • 1、這周工作上主要是涉及了兩件事布疙,一件是能否做到實(shí)時(shí)針對(duì)門的識(shí)別和標(biāo)示蚊惯,二是能否利用二維碼判斷出機(jī)器人的相對(duì)位姿。...
    呂鵬_hunhun閱讀 242評(píng)論 0 2