这篇文章讲一下 JavaScriptCore,它是从 iOS7 开始加入的,这个框架其实只是基于 webkit 中以 C/C++ 实现的JavaScriptCore的一个包装,该框架让Objective-C、Swift 和 JavaScript 代码直接的交互变得更加的简单方便
关于 JavaScriptCore 的使用可以先看这两篇文章:
NSHipster 中文版的 JavaScriptCore
看了上面两篇文章应该对 JavaScriptCore 有了基本的了解
1、简要介绍JavaScriptCore
使用 JavaScriptCore 需要先导入框架 import JavaScriptCore
,JavaScriptCore
主要有五个类:
- JSContext
- JSValue
- JSManagedValue
- JSVirtualMachine
- JSExport
1.1 JSVirtualMachine
JSVirtualMachine
看名字直译是 JS 虚拟机,也就是说JavaScript是在一个虚拟的环境中执行,而 JSVirtualMachine
为其执行提供底层资源:
|
|
一个 JSVirtualMachine
实例,代表一个独立的 JavaScript
对象空间,并为其执行提供资源,它通过加锁虚拟机,保证 JSVirtualMachine
是线程安全的,如果要并发执行 JavaScript
,那我们必须创建多个独立的 JSVirtualMachine
实例,在不同的实例中执行 JavaScript
通过 alloc/init
就可以创建一个新的 JSVirtualMachine
对象,但是我们一般不用新建 JSVirtualMachine
对象,因为创建 JSContext
时,如果我们不提供一个特性的 JSVirtualMachine
,内部会自动创建一个 JSVirtualMachine
对象
1.2 JSContext和JSValue
JSVirtualMachine
为 JavaScript
的运行提供了底层资源,JSContext
就为其提供着运行环境,JSContext
也管理 JSVirtualMachine
中对象的生命周期。每一个 JSValue
对象都要强引用关联一个 JSContext
,当与某 JSContext
对象关联的所有 JSValue
释放后,JSContext
也会被释放
创建一个JSContext对象的方式下面三种:
|
|
本文使用方式3来创建JSContext
JSValue 包括一系列方法用于访问其可能的值以保证有正确的 Foundation 类型,包括:
JavaScript Type | JSValue method | Objective-C Type | Swift Type |
---|---|---|---|
boolean | toBool | BOOL | Bool |
number | toNumber | NSNumber | NSNumber! |
Date | toDate | NSDate | NSDate! |
Array | toArray | NSArray | [AnyObject]! |
Object | toDictionary | NSDictionary | [NSObject : AnyObject]! |
Object | toObject | custom type | custom type |
1.3 JSManagedValue
JSManagedValue
主要用途是解决 JSValue
对象在堆上的安全引用问题,把JSValue
保存进堆对象中是不正确的,这很容易引发循环引用,而导致JSContext不能释放,这个类主要是将JSValue对象转换为JSManagedValue的API,而且也不常用,就不做具体介绍了
1.4 JSExport
JSExport
是一个协议类,但是该协议并没有任何属性和方法,我们可以自定义一个协议类,继承自JSExport
无论我们在JSExport里声明的属性,实例方法还是类方法,继承的协议都会自动的提供给任何 JavaScript
代码,我们只需要在自定义的协议类中,添加上属性和方法就可以了
2 使用 JavaScriptCore 实现 JS 与 Swift 互调
2.1 创建 UIWebView,并加载本地HTML
这部分和之前的 iOS下JS与Swift互相调用(一)UIWebView拦截URL 一样:
|
|
HTML 的内容也大致一样,不过 JS 的调用有些区别:
|
|
|
|
详细请看文章末尾的源码
2.2 添加 JS 要调用的原生 Swift 方法
让 JSContext
访问我们的 Swift 代码的方式主要有两种:block 和 JSExport 协议,这里有一个小问题,需要注意:block 方法仅仅适用于 OC 的block,并不适用于 Swift 中的闭包,为了公开闭包,我们将进行如下两步操作:
- 使用@convention(block) 属性标记闭包,来建立桥梁成为 OC 中的block
- 在映射block到JavaScript方法调用之前,我们需要unsafeBitCast函数将block转成为AnyObject
本文只讨论 JSExport 协议的方式使用 JavaScriptCore,在 webViewDidFinishLoad
代理方法里面注入一个叫 JavaScriptCoreBridge
的对象,这个对象用来充当原生应用和 Web 页面之间的一个桥梁
|
|
自定义 SwiftJavaScriptDelegate
协议,而且此协议必须遵守 JSExport
协议,自定义协议中的方法就是暴露给 Web 页面的方法,在 webView 加载完毕的时候获取 JS 运行的上下文环境,然后再注入桥梁对象名为JavaScriptCoreBridge
,承载的对象为 self 即为此控制器,控制器遵守此自定义协议实现协议中对应的方法, 在 JS 调用完本地应用的方法做完相对应的事情之后,又回调了 JS 中对应的方法,从而实现了 Web 页面和本地应用之间的通讯:
|
|
这里有两点需要注意:
自定义协议必须使用
@objc
,因为JavaScriptCore
库是 Objective C版本的,如果不加@objc
,在 Swift 则调用无效果自定义协议里面的方法,如果是需要传多个参数(大于一个),JS 调用时就要对应的跟上参数的名字,第一个参数名可以省略,什么意思呢?看下面的代码:
12345678 // 这是协议里面的方法的写法//多参数注意 js里面的方法的写法,需要在方法名里带参数名func share(_ title: String, content: String, url:String)//这是 JS 里对应方法的写法var shareClick = function () {JavaScriptCoreBridge.shareContentUrl('测试分享的标题','测试分享的内容','http://www.baidu.com');}
上面第二点注意的原因我目前也不清楚,只能这样写才 JS 能顺利的调用 Swift 的方法,所以为了避免这些麻烦,我建议不管多少个参数,都改成传一个 Json 字符串,这样就避免了 JS 里方法的写法问题,demo 里面支付信息有多个参数我就是把多个参数转成一个 Json 字符串传给 Swift :
|
|
2.3 JS 和 Swift 的相互调用
上面的准备工作完成之后,JS 和 Swift 的相互调用就很简单了,控制器遵守自定义的 SwiftJavaScriptDelegate
的协议,并实现协议里的方法:
|
|
这样就完成了 JS 调用 Swift,Swift 调用 JS 的方式就有多种了:
方式一:JSContext 的
evaluateScript
方法1JSContext.current().evaluateScript("payResult('支付成功')")方式二:使用 JSValue 的
callWithArguments
方法1JSContext.current().objectForKeyedSubscript("payResult").call(withArguments: ["支付成功"])方式三:之前介绍的 UIWebView 的
stringByEvaluatingJavaScript
方法1self.webView?.stringByEvaluatingJavaScript(from: "payResult('支付成功')")
3 JavaScriptCore 的补充说明
使用JavaScriptCore,JS调用Native方法时,参数的传递更方便,不用担心特殊符号的转换问题,由于WKWebView 不支持通过如下的 KVC 的方式创建 JSContext:
|
|
所以就不能在 WKWebView 中使用 JavaScriptCore,但是 WKWebView 可以使用WKScriptMessageHandler 的方式和 JS 交互,这种方式更加简单方便
原文地址: iOS 下 JS 与 OC 互相调用(四)– JavaScriptCore
原文是讨论 OC 与 JS 的交互,我按照作者的思路,用 Swift 实现 Native 与 JS 的交互,这是 代码地址
更多参考文章:
iOS 开发 - Swift 使用 JavaScriptCore 与 JS 交互
Objective-C 与 JavaScript 交互的那些事
JavaScriptCore 基本概念和基本使用(Swift)
本人刚开始写博客,主要是为了给自己的知识点做一个笔记,方便自己以后查阅,如果能让别人有所启发也是荣幸之至!如有错误,欢迎指正!