UIWebView與JS交互

iOS中webView有兩種虹菲,一種是UIWebView靠胜,在iOS8之前使用,比較笨重毕源、耗內(nèi)存浪漠,另一種是WKWebView,是iOS8以及以上版本新框架霎褐,用于取代UIWebVIew址愿,開(kāi)發(fā)項(xiàng)目如果適配最低版本為8.0以上都應(yīng)該使用WKWebView,UIWebView和WKWebView都可以和JS進(jìn)行交互冻璃,但是交互實(shí)現(xiàn)方式不相同响谓,本文主要講UIWebView與JS交互,至于WKWebView我會(huì)另外寫(xiě)一篇文章講解如何與JS交互省艳。(已寫(xiě)好WKWebView與JS交互)

準(zhǔn)備工作:在控制器上添加UIWebView并加載本地HTML文件

override func viewDidLoad() {
        super.viewDidLoad()
        let web = UIWebView(frame: view.frame)
        view.addSubview(web)
        
        web.delegate = self
        let path = Bundle.main.path(forResource: "test", ofType: "html")
        let url = URL(fileURLWithPath: path!)
        let request = URLRequest(url: url)
        web.loadRequest(request)
    }

遵循UIWebViewDelegate協(xié)議實(shí)現(xiàn)代理webViewDidFinishLoad(_ webView: UIWebView)

1.UIWebView調(diào)用JS方法

不管是UIWebView調(diào)用JS還是JS調(diào)用UIWebView都需要先獲取JSContext娘纷,所以先引入JavaScriptCore并定義一個(gè)JSContext變量

import JavaScriptCore
var jsContext: JSContext?

然后在webViewDidFinishLoad(_ webView: UIWebView)中給其賦值

self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext

1.1 UIWebView調(diào)用JS無(wú)參數(shù)方法

如果JS中有一個(gè)方法叫Swift_JS1,我們可以這樣調(diào)用

self.context?.evaluateScript("Swift_JS1()")

1.2 UIWebView調(diào)用JS有參數(shù)方法

如果JS中有一個(gè)方法叫做Swift_JS2并帶有兩個(gè)參數(shù)跋炕,我們不用管參數(shù)名赖晶,也不用管參數(shù)類型,可以這樣調(diào)用:(我傳的兩個(gè)字符串辐烂,其他類型也可以傳)

self.context?.evaluateScript("Swift_JS2('oc' ,'Swift')")

除了這樣傳參數(shù)遏插,還有一種方式
比如JS中有一個(gè)叫swiftAndJS的方法,參數(shù)是要我們傳一張圖片纠修,我們可以這樣調(diào)用

 let pic = #imageLiteral(resourceName: "icon_buy")
 let jsFunc = self.jsContext?.objectForKeyedSubscript("swiftAndJS")
 let _ = jsFunc?.call(withArguments: [pic])

2. JS調(diào)用Swift方法

js調(diào)用UIWebView可以通過(guò)注入模型調(diào)用胳嘲。

第一步:
先定義一個(gè)協(xié)議并遵循JSExport,我這里給協(xié)議取名叫JavaScriptSwiftDelegate并定義兩個(gè)方法openCamera()(無(wú)參數(shù))和callWithDict(_ dict: [String: AnyObject])(有參數(shù)),JS可通過(guò)這個(gè)調(diào)用模型方法扣草。實(shí)際開(kāi)發(fā)中胎围,js要調(diào)用的方法需要在這里面聲明,方法名字需要和JS端協(xié)商德召,因?yàn)镴S調(diào)用時(shí)需要使用這個(gè)名字白魂。

import JavaScriptCore

@objc protocol JavaScriptSwiftDelegate: JSExport{
    func openCamera()
    func callWithDict(_ dict: [String: AnyObject])
}

第二步:
建立模型,遵循剛才的協(xié)議并實(shí)現(xiàn)協(xié)議方法上岗,我這里建立模型取名JSModelSwift福荸,JS請(qǐng)求打開(kāi)相機(jī)我就在控制臺(tái)打印了一下表示調(diào)用成功,傳參方法將參數(shù)打印

@objc class JSModelSwift: NSObject, JavaScriptSwiftDelegate {
    
    weak var jsContex: JSContext?
    
    func openCamera() {
        print("JS請(qǐng)求打開(kāi)相機(jī)")
    }

   func callWithDict(_ dict: [String : AnyObject]) {
        print("js調(diào)用了方法肴掷,參數(shù)是: \(dict)")
    }
}

第三步:
func webViewDidFinishLoad(_ webView: UIWebView)中注入模型,其中SwiftModel也是需要和JS端協(xié)商敬锐,JS端調(diào)用UIWebView方法時(shí)需要使用這個(gè)模型名字

//MARK: 注入模型調(diào)用
        let model = JSModelSwift()
        model.jsContex = self.jsContext
        //注入模型
        //將模型注入jsContext后背传,js端可以通過(guò)SwiftModel調(diào)用Swift模型中的方法
        self.jsContext?.setObject(model, forKeyedSubscript: "SwiftModel" as NSCopying & NSObjectProtocol)

第四步:
在JS中調(diào)用該方法,定義兩個(gè)按鈕台夺,點(diǎn)擊按鈕后調(diào)用打開(kāi)相機(jī)方法和傳參方法

<div style="margin-top: 100px">
            <input type="button" value="調(diào)用系統(tǒng)相機(jī)" onclick="SwiftModel.openCamera()">
 </div>

<div>
            <input type="button" value="調(diào)用方法并傳參" onclick="SwiftModel.callWithDict({'name': 'testname', 'age': 10, 'height': 170})"> 
</div>

全部代碼如下:
ViewController

import UIKit
import JavaScriptCore

class ViewController: UIViewController, UIWebViewDelegate {
    
    var jsContext: JSContext?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let web = UIWebView(frame: view.frame)
        view.addSubview(web)
        
        web.delegate = self
        let path = Bundle.main.path(forResource: "test", ofType: "html")
        let url = URL(fileURLWithPath: path!)
        let request = URLRequest(url: url)
        web.loadRequest(request)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
            self.callJSFunc()
        }
    }
    
    func webViewDidFinishLoad(_ webView: UIWebView) {
        
        self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext
        
        //MARK: 注入模型調(diào)用
        let model = JSModelSwift()
        model.jsContex = self.jsContext
        //注入模型
        //將模型注入jsContext后径玖,js端可以通過(guò)SwiftModel調(diào)用Swift模型中的方法
        self.jsContext?.setObject(model, forKeyedSubscript: "SwiftModel" as NSCopying & NSObjectProtocol)
        
    }
    
    
    //swift調(diào)用js方法
    func callJSFunc(){
        
        let pic = #imageLiteral(resourceName: "icon_buy")
        let jsFunc = self.jsContext?.objectForKeyedSubscript("swiftAndJS")
        let _ = jsFunc?.call(withArguments: [pic])
    }
    
    
}

JSModelSwift

import UIKit
import JavaScriptCore

@objc protocol JavaScriptSwiftDelegate: JSExport{
    func openCamera()
    func callWithDict(_ dict: [String: AnyObject])
}

@objc class JSModelSwift: NSObject, JavaScriptSwiftDelegate {
    
    weak var jsContex: JSContext?
    
    func openCamera() {
        print("JS請(qǐng)求打開(kāi)相機(jī)")
    }
    
    func callWithDict(_ dict: [String : AnyObject]) {
        print("js調(diào)用了方法,參數(shù)是: \(dict)")
    }

}

html

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>首頁(yè)</title>
    </head>
    
    <script type="text/javascript">
        
        function swiftAndJS(pic){
            alert("Swift調(diào)用了有參數(shù)的js方法,參數(shù)為" + pic);
        }
    </script>
    
    <body bgcolor="#dddd">
        
        <!--      模型注入     -->
        <div style="margin-top: 100px">
            <input type="button" value="調(diào)用系統(tǒng)相機(jī)" onclick="SwiftModel.openCamera()">
        </div>
        
        <div>
            <input type="button" value="調(diào)用方法并傳參" onclick="SwiftModel.callWithDict({'name': 'testname', 'age': 10, 'height': 170})">
        </div>
        
    </body>
</html>


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颤介,一起剝皮案震驚了整個(gè)濱河市梳星,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滚朵,老刑警劉巖冤灾,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辕近,居然都是意外死亡韵吨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)移宅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)归粉,“玉大人,你說(shuō)我怎么就攤上這事漏峰】返浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵芽狗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我痒蓬,道長(zhǎng)童擎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任攻晒,我火速辦了婚禮顾复,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲁捏。我一直安慰自己芯砸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布给梅。 她就那樣靜靜地躺著假丧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪动羽。 梳的紋絲不亂的頭發(fā)上包帚,一...
    開(kāi)封第一講書(shū)人閱讀 52,584評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音运吓,去河邊找鬼渴邦。 笑死疯趟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谋梭。 我是一名探鬼主播信峻,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓮床!你這毒婦竟也來(lái)了盹舞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤纤垂,失蹤者是張志新(化名)和其女友劉穎矾策,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體峭沦,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贾虽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吼鱼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓬豁。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖菇肃,靈堂內(nèi)的尸體忽然破棺而出地粪,到底是詐尸還是另有隱情,我是刑警寧澤琐谤,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布蟆技,位于F島的核電站,受9級(jí)特大地震影響斗忌,放射性物質(zhì)發(fā)生泄漏质礼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一织阳、第九天 我趴在偏房一處隱蔽的房頂上張望眶蕉。 院中可真熱鬧,春花似錦唧躲、人聲如沸造挽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饭入。三九已至,卻和暖如春肛真,著一層夾襖步出監(jiān)牢的瞬間圣拄,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工毁欣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庇谆,地道東北人岳掐。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饭耳,于是被迫代替她去往敵國(guó)和親串述。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

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