iOS中调用JS
先写JS操作语句,再通过IOS中的webView执行这个条JS语句。
使用UIwebView调用的是stringByEvaluatingJavaScript(from:jsStr)这个方法
使用WKWebView调用的是evaluateJavaScript(jsStr) { (result, error) in }
示例:增删改查
|
|
JS调用iOS
利用WKWebView的新特性MessageHandler来实现JS调用原生方法带来的好处:
1、在JS中写起来简单,不用再用创建URL的方式那么麻烦了
2、JS传递参数更方便。使用拦截URL的方式传递参数,只能把参数拼接在后面,如果遇到要传递的参数中有特殊字符,如&、=、?等,必须得转换,否则参数解析肯定会出错。
示例:在html页面点击登录按钮,把账号和密码传给iOS端;点击html页面的访问相册按钮,访问手机系统相册
遵守协议WKScriptMessageHandler,UINavigationControllerDelegate,UIPickerViewDelegate
JavaScriptCore框架
JavaScriptCore框架其实就是基于webkit中以C/C++实现的JavaScriptCore的一个包装,
还提供了Objective-C的封装接口,不过只能使用在iOS 7以上。
(JavaScriptCore是苹果Safari浏览器的JavaScript引擎,类似于Google的V8引擎)
主要的类
1、JSContext — 在OC中创建JavaScript运行的上下文环境
示例:创建JSContext
2、JSValue — 可以转成OC数据类型,JSContext强引用着JSValue
OC与JS数据类型对比、转换
3、JSExport — 一个协议类,通过协议的方式把OC的属性和方法暴露给JS使用(自定义一个继承自JSExport协议的协议,并实现协议)
4、JSManagedValue — 主要用途是解决JSValue对象在Objective-C 堆上的安全引用问题。把JSValue 保存进Objective-C 堆对象中是不正确的,这很容易引发循环引用,而导致JSContext不能释放。这个类主要是将JSValue对象转换为JSManagedValue的API
5、JSVirtualMachine — JS虚拟机,也就是说JavaScript是在一个虚拟的环境中执行,而JSVirtualMachine为其执行提供底层资源。有独立的堆空间和垃圾回收机制,运行在不同虚拟机环境的JSContext可以通过此类通信。
一个JSVirtualMachine实例,代表一个独立的JavaScript对象空间,并为其执行提供资源。它通过加锁虚拟机,保证JSVirtualMachine是线程安全的,如果要并发执行JavaScript,那我们必须创建多个独立的JSVirtualMachine实例,在不同的实例中执行JavaScript。
通过alloc/init就可以创建一个新的JSVirtualMachine对象。但是我们一般不用新建JSVirtualMachine对象,因为创建JSContext时,如果我们不提供一个特性的JSVirtualMachine,内部会自动创建一个JSVirtualMachine对象。
OC调用JS方法
示例一:OC调用JS(页内js)
方式1:使用JSContext的方法-evaluateScript
方式2:使用JSValue的方法-callWithArguments
示例二:OC调用JS(页外js)的平方方法
JS文件(square.js)的代码
OC中的代码
JS调用OC的方法
第一种使用block的方式:
将OC中的单个方法(即block)暴露给JS调用,JavaScriptCore框架会自动将这个Block包装成一个JS方法。
注意:使用black可能造成内存泄露的问题
不要在Block中直接使用JSValue,建议把JSValue当做参数传到Block中,这样Block就不会强引用JSValue了。
不要在Block中直接使用JSContext,可以使用[JSContext currentContext] 方法来获取当前的Context。
示例:
|
|
第二种使用JSExport协议的方式:
使用JSExport协议将OC中某个对象直接暴露给JS使用,而且在JS中使用就像调用JS的对象一样自然
示例:
|
|
内存管理注意事项
1、不要在JS中给OC对象增加成员变量
2、OC对象不要直接强引用JSValue对象,解决方案:苹果推出了一种新的引用关系,叫conditional retain,有条件的强引用,JSManagedValue就是苹果用来实现conditional retain的类。JSManagedValue弱引用着JSValue
补充:
关于WKWebView 与JavaScriptCore,由于WKWebView 不支持通过如下的KVC的方式创建JSContext:
但WKWebView与JS交互有特有的方式:MessageHandler,在上文已介绍过。
多线程
说多线程之前得先说下另一个类JSVirtualMachine,它为JavaScript的运行提供了底层资源,有自己独立的堆栈以及垃圾回收机制。
JSVirtualMachine还是JSContext的容器,可以包含若干个JSContext,在一个进程中,你可以有多个JSVirtualMachine,里面包含着若干个JSContext,而JSContext中又有若干个JSValue。
需要注意的是,你可以在同一个JSVirtualMachine的不同JSContext中,互相传递JSValue,但是不能再不同的JSVirtualMachine中的JSContext之间传递JSValue。
这是因为,每个JSVirtualMachine都有自己独立的堆栈和垃圾回收器,一个JSVirtualMachine的垃圾回收器不知道怎么处理从另一个堆栈传过来的值。
JavaScriptCore提供的API本身就是线程安全的,你可以在不同的线程中,创建JSValue,用JSContext执行JS语句,但是当一个线程正在执行JS语句时,其他线程想要使用这个正在执行JS语句的JSContext所属的JSVirtualMachine就必须得等待,等待前前一个线程执行完,才能使用这个JSVirtualMachine。
当然,这个强制串行的粒度是JSVirtualMachine,如果你想要在不用线程中并发执行JS代码,可以为不同的线程创建不同JSVirtualMachine。