iOS開發 - Swift使用JavaScriptCore與JS交互


一、前言

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

下載地址:

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

二、JavaScriptCore中的類

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

三、交互方式主要有兩種

一)、 在Swift中,通過JSContext直接執行JS代碼

import JavaScriptCore    //記得導入JavaScriptCore


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

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

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

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

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

1. 首先定義定義協議SwiftJavaScriptDelegate 該協議必須遵守JSExport協議

@objc protocol SwiftJavaScriptDelegate: JSExport {

    // js調用App的微信支付功能 演示最基本的用法
    func wxPay(orderNo: String)

    // js調用App的微信分享功能 演示字典參數的使用
    func wxShare(dict: [String: AnyObject])

    // js調用App方法時傳遞多個參數 並彈出對話框 注意js調用時的函數名
    func showDialog(title: String, message: String)

    // js調用App的功能后 App再調用js函數執行回調
    func callHandler(handleFuncName: String)

}

2. 然后定義一個模型 該模型實現SwiftJavaScriptDelegate協議

@objc class SwiftJavaScriptModel: NSObject, SwiftJavaScriptDelegate {

    weak var controller: UIViewController?
    weak var jsContext: JSContext?

    func wxPay(orderNo: String) {

        print("訂單號:", orderNo)

        // 調起微信支付邏輯
    }

    func wxShare(dict: [String: AnyObject]) {

        print("分享信息:", dict)

        // 調起微信分享邏輯
    }

    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加載對應的網頁,這里加載例子中的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!)

    // 加載網絡Html頁面 請設置允許Http請求
    //let url = NSURL(string: "http://www.mayanlong.com");
    //let request = NSURLRequest(URL: url!)

    self.webView.loadRequest(request)
}

4. 最后在webViewDidFinishLoad代理中將我們定義的模型注入到網頁中,暴露給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調用我們暴露的方法了。
    self.jsContext.setObject(model, forKeyedSubscript: "WebViewJavascriptBridge")

    // 注冊到本地的Html頁面中
    let url = NSBundle.mainBundle().URLForResource("demo", withExtension: "html")
    self.jsContext.evaluateScript(try? String(contentsOfURL: url!, encoding: NSUTF8StringEncoding))

    // 注冊到網絡Html頁面 請設置允許Http請求
    //let url = "http://www.mayanlong.com";
    //let curUrl = self.webView.request?.URL?.absoluteString    //WebView當前訪問頁面的鏈接 可動態注冊
    //self.jsContext.evaluateScript(try? String(contentsOfURL: NSURL(string: url)!, encoding: NSUTF8StringEncoding))

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

5. Swift與JS方法互相調用

JS調用Swift方法

WebViewJavascriptBridge.wxPay('TN20160526')

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

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

Swift調用JS方法並傳參

func callHandler(handleFuncName: String) {

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

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

四、代碼下載及效果圖

下載地址:

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

效果圖:

Swift與JS交互效果

本文首發於馬燕龍個人博客,歡迎分享,轉載請標明出處。
馬燕龍個人博客:http://www.mayanlong.com
馬燕龍個人微博:http://weibo.com/imayanlong 
馬燕龍Github主頁:https://github.com/yanlongma

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM