iOS開發(fā) - Swift使用JavaScriptCore與JS交互

一、前言

在這個提倡敏捷開發(fā)和H5橫行的年代,原生App內(nèi)嵌入一些H5頁面已經(jīng)成為一種流行的趨勢。一套H5頁面就可以適配復(fù)雜的iOS和Android頁面,大量節(jié)省了開發(fā)和維護時間,如果本來就有移動端網(wǎng)頁,只需簡單適配即可完成,那我們何樂而不為呢?蘋果也順應(yīng)了潮流,在iOS7中提供了JavaScriptCore框架用來與網(wǎng)頁中的JS進行交互。還有Facebook推出的React Native,也給跨平臺開發(fā)提供了新的思路和解決方案,雖然目前它還不是很成熟。但作為一個開發(fā)者,對這些新技術(shù)的出現(xiàn)自然會感到無比的興奮。本文主要介紹iOS開發(fā)中,Swift如何使用JavaScriptCore與網(wǎng)頁中的JS進行交互。

下載地址:

Github:https://github.com/YanlongMa/SwiftJavaScriptCore
如果本Demo對您有幫助,請不要吝嗇您的Start(⊙o⊙)哦。

二、JavaScriptCore中的類

  • JSContext:JSContext是JS的執(zhí)行環(huán)境,通過evaluateScript()方法可以執(zhí)行JS代碼
  • JSValue:JSValue封裝了JS與ObjC中的對應(yīng)的類型,以及調(diào)用JS的API等
  • JSExport:JSExport是一個協(xié)議,遵守此協(xié)議,就可以定義我們自己的協(xié)議,在協(xié)議中聲明的API都會在JS中暴露出來,這樣JS才能調(diào)用原生的API

三、交互方式主要有兩種

一). 在Swift中,通過JSContext直接執(zhí)行JS代碼

import JavaScriptCore    //記得導(dǎo)入JavaScriptCore


// 通過JSContext執(zhí)行js代碼
let context: JSContext = JSContext()
let result1: JSValue = context.evaluateScript("1 + 3")
print(result1)  // 輸出4

// 定義js變量和函數(shù)
context.evaluateScript("var num1 = 10; var num2 = 20;")
context.evaluateScript("function sum(param1, param2) { return param1 + param2; }")

// 通過js方法名調(diào)用方法
let result2 = context.evaluateScript("sum(num1, num2)")
print(result2)  // 輸出30

// 通過下標(biāo)來獲取js方法并調(diào)用方法
let squareFunc = context.objectForKeyedSubscript("sum")
let result3 = squareFunc.callWithArguments([10, 20]).toString()
print(result3)  // 輸出30

二). 在Swift中通過JSContext注入模型,然后調(diào)用模型的方法

1. 首先定義定義協(xié)議SwiftJavaScriptDelegate 該協(xié)議必須遵守JSExport協(xié)議

@objc protocol SwiftJavaScriptDelegate: JSExport {
    
    // js調(diào)用App的微信支付功能 演示最基本的用法
    func wxPay(orderNo: String)
    
    // js調(diào)用App的微信分享功能 演示字典參數(shù)的使用
    func wxShare(dict: [String: AnyObject])
    
    // js調(diào)用App方法時傳遞多個參數(shù) 并彈出對話框 注意js調(diào)用時的函數(shù)名
    func showDialog(title: String, message: String)
    
    // js調(diào)用App的功能后 App再調(diào)用js函數(shù)執(zhí)行回調(diào)
    func callHandler(handleFuncName: String)
    
}

2. 然后定義一個模型 該模型實現(xiàn)SwiftJavaScriptDelegate協(xié)議

@objc class SwiftJavaScriptModel: NSObject, SwiftJavaScriptDelegate {
    
    weak var controller: UIViewController?
    weak var jsContext: JSContext?
    
    func wxPay(orderNo: String) {
    
        print("訂單號:", orderNo)
        
        // 調(diào)起微信支付邏輯
    }
    
    func wxShare(dict: [String: AnyObject]) {
        
        print("分享信息:", dict)
        
        // 調(diào)起微信分享邏輯
    }
    
    func showDialog(title: String, message: String) {
        
        let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "確定", style: .Default, handler: nil))
        self.controller?.presentViewController(alert, animated: true, completion: nil)
    }
    
    func callHandler(handleFuncName: String) {
        
        let jsHandlerFunc = self.jsContext?.objectForKeyedSubscript("\(handleFuncName)")
        let dict = ["name": "sean", "age": 18]
        jsHandlerFunc?.callWithArguments([dict])
    }
}

3. 然后使用WebView加載對應(yīng)的網(wǎng)頁,這里加載例子中的demo.html文件

func addWebView() {
    
    self.webView = UIWebView(frame: self.view.bounds)
    self.view.addSubview(self.webView)
    self.webView.delegate = self
    self.webView.scalesPageToFit = true
    
    // 加載本地Html頁面
    let url = NSBundle.mainBundle().URLForResource("demo", withExtension: "html")
    let request = NSURLRequest(URL: url!)
    
    // 加載網(wǎng)絡(luò)Html頁面 請設(shè)置允許Http請求
    //let url = NSURL(string: "http://www.mayanlong.com");
    //let request = NSURLRequest(URL: url!)
    
    self.webView.loadRequest(request)
}

4. 最后在webViewDidFinishLoad代理中將我們定義的模型注入到網(wǎng)頁中,暴露給JS

func webViewDidFinishLoad(webView: UIWebView) {
    
    
    self.jsContext = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as! JSContext
    let model = SwiftJavaScriptModel()
    model.controller = self
    model.jsContext = self.jsContext
    
    // 這一步是將SwiftJavaScriptModel模型注入到JS中,在JS就可以通過WebViewJavascriptBridge調(diào)用我們暴露的方法了。
    self.jsContext.setObject(model, forKeyedSubscript: "WebViewJavascriptBridge")
    
    // 注冊到本地的Html頁面中
    let url = NSBundle.mainBundle().URLForResource("demo", withExtension: "html")
    self.jsContext.evaluateScript(try? String(contentsOfURL: url!, encoding: NSUTF8StringEncoding))
    
    // 注冊到網(wǎng)絡(luò)Html頁面 請設(shè)置允許Http請求
    //let url = "http://www.mayanlong.com";
    //let curUrl = self.webView.request?.URL?.absoluteString    //WebView當(dāng)前訪問頁面的鏈接 可動態(tài)注冊
    //self.jsContext.evaluateScript(try? String(contentsOfURL: NSURL(string: url)!, encoding: NSUTF8StringEncoding))

    self.jsContext.exceptionHandler = { (context, exception) in
        print("exception:", exception)
    }
}

5. Swift與JS方法互相調(diào)用

JS調(diào)用Swift方法

WebViewJavascriptBridge.wxPay('TN20160526')

WebViewJavascriptBridge.wxShare({
            'title' : '馬燕龍個人博客',
            'description' : '一個專注于編程的技術(shù)博客',
            'url' : 'http://www.mayanlong.com'
        })

WebViewJavascriptBridge.showDialogMessage('馬燕龍個人博客', '一個專注于編程的技術(shù)博客')

Swift調(diào)用JS方法并傳參

func callHandler(handleFuncName: String) {
    
    let jsHandlerFunc = self.jsContext?.objectForKeyedSubscript("\(handleFuncName)")
    let dict = ["name": "sean", "age": 18]
    jsHandlerFunc?.callWithArguments([dict])
}

這樣,我們就實現(xiàn)了Swift與JS的交互了,Demo中給出了詳細(xì)的代碼,大家可以下載運行。

四、代碼下載及效果圖

下載地址:

Github:https://github.com/YanlongMa/SwiftJavaScriptCore
如果本Demo對您有幫助,請不要吝嗇您的Start(⊙o⊙)哦。

效果圖:

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

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

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