美文网首页iOS资料iOS开发周刊macOS
iOS开发 - Swift使用JavaScriptCore与JS

iOS开发 - Swift使用JavaScriptCore与JS

作者: 天秤vs永恒 | 来源:发表于2016-06-08 18:55 被阅读3565次

    一、前言

    在这个提倡敏捷开发和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交互效果

    相关文章

      网友评论

      • DDDDogGG:感谢分享。
        我根据自己的测试,补充两个注意点
        1. JSExport 子协议的方法必须省略实参标签
        2. JSExport 子协议和遵循这个协议的模型类都必须声明为 @objc
      • 一声雷:SwiftJavaScriptModel这个内存不能释放,不知道作者有没解决这个问题?
      • e93a21ed28a8:如果js的方法写在js标签里面呢,怎么通过js调用swift里的方法,并且传递参数
        e93a21ed28a8:@天秤vs永恒 可我这不知道咋回事,参数传不出去:cold_sweat:
        天秤vs永恒:@豆腐小僧 一样的
      • the_uncle:你好 在吗 有点问题想要咨询你
        the_uncle:@天秤vs永恒 谢谢了 我已经解决了
        天秤vs永恒:@the_uncle 在下面直接问就好了!
      • 帅气的华子:总结的到位,点赞

      本文标题:iOS开发 - Swift使用JavaScriptCore与JS

      本文链接:https://www.haomeiwen.com/subject/vlmjdttx.html