YGben

iOS与H5交互


书到用时方恨少,南方的九月依然炎热,着不住家里小亭的凉风。还好快国庆回家了。

  • 目前开发App有 哪些模式
  • 运用JavaScriptCore框架
  • 解析JavaScriptCore框架

常见的五种App开发模式

这里小小总结下:

  1. Native App
  2. Web App (比如 小程序)
  3. Hybrid App
  4. Weex(或Vue)
  5. React Native

本篇主要是 Hybrid App iOS中 OC与H5 的交互。

Hybrid App

混合开发就离不了H5与原生的交互,最近项目需求用到js与原生的交互,只不过我开发的H5部分。

在这里也总结以下交互的解决方式:(从iOS角度)

  1. 运用 UIWebView (针对iOS7.0以前)
  2. 运用 WKWebView (iOS8推出,苹果建议iOS8.0使用)
  3. 运用 JavaScriptCore 框架(iOS7.0后)
  4. 运用第三方优秀框架 (例如 @Marcus Westin开源库 WebViewJavascriptBridge

前两者方法利用 UIWebView或者WKWebView 的系统方法调用JS方法,iOS7.0前JS调用OC代码,方法名在URL中,截取URL获取方法名,再调用OC的同名方法。WKWebView可以利用协议方法。具体用到可以谷歌。

JavaScriptCore

JavaScriptCore 很好的解决了OC和JS的互相调用,不用依托控制器UIWebView或者WKWebView。
对于JavaScriptCore的理解,我更想把她理解为嵌入到OC代码中的JS引擎。或许不对,对于JS还不够深入。我也是看了这篇 一篇给小白看的 JavaScript 引擎指南了解,构成 Webkit 实现基础的 JavaScript 引擎就是 JavaScriptCore。还有一篇介绍 JS内核和引擎
主要类:

JSContext: 提供JS的执行环境,简直就是基石本质。所有JS代码执行都依靠JSContext。
来源  @殷源 JavaScriptCore全面解析

JSValue: 注入JS代码中的变量载体,完美转换原生和JS的变量。变量,除了基本数据类型,可以是自定义类或者方法。JSValue 所有实例来源JSContext。

JSManagedValue: 本质上是一个JSValue,但是可以处理内存管理中的一些特殊情形。

例子:

JSValue *nickName = [JSValue valueWithObject:name inContext:context];
JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:nickName  andOwner:self];
context[@"block"] = ^(){
NSLog(@"nickName:%@\ncurrentContext:%@",
[managedValue value],[JSContext currentContext]);
};
[context evaluateScript:@"block()"];

JSValue对象 nickName 持有强引用 context,context中注入block,并调用 JSValue对象和 context,互相持有,所以可能产生 循环引用。

JSExport: 协议,可以将原生对象,方法和属性转为JS的变量,简直就是黑魔法。

JSVirtualMachine: 官方解释此类提供JS执行的工作空间。主要两个用途:支持并发JavaScript执行,并管理JavaScript和Objective-C或Swift之间桥接的对象的内存。
这句代码JSContext *context = [[JSContext alloc] init]; 使用 context.virtualMachine 就可以输出默认创建的JSVirtualMachine。每一个JavaScript上下文(JSContext对象)都归属于一个虚拟机(JSVirtualMachine)。每个虚拟机可以包含多个不同的上下文,并允许在这些不同的上下文之间传值(JSValue对象),但是不允许两个虚拟机之间传旨,因为垃圾回收站(GC)无法处理虚拟机堆中对象。

基础使用

具体的使用就不啰嗦了,很多本文的分享链接都有写到。自己写代码敲一遍基本就了解了。

  • (JSValue )evaluateScript:(NSString )script;

执行JS代码。当然调用js代码也可以这样:

JSValue function = context[@”printHello”];
JSValue
result = [function callWithArguments:@[@”YGben”]];

含义:取出context的方法printHello;执行并传参数“YGben”

  • (void)setObject:(id)object forKeyedSubscript:(NSObject *)key;

给JS中代码变量 key 赋值属性 object

其实JavaScriptCore实现了JS和OC 的互联互通,谁调谁就看业务需求,主要看谁的参数传给谁,谁接受参数处理,如果OC接受参数处理,就是JS调用原生方法。如果JS接受参数处理,就是原生方法调JS。

注意

参考 腾讯 @殷源JavaScriptCore全面解析(下篇), 总结 JavaScriptCore,大量参考了该文,表示感谢。

  1. JS调用OC代码两种方式:
  • Block直接赋值,调用JS命名的方法实质就在调用Block
  • 遵循JSExport协议
  1. 内存管理 看懂这两张图

正常持有
如果我们在native对象中强引用持有JSContext或者JSValue,便会造成循环引用

参考传送门

swift版本JavaScriptCore
gitbook @HJGitBook 有关 JavaScriptCore 的博文
简书@ 袁峥 的一篇JavaScriptCore用法 的博文
@ KittenYang UIWebView与JS的深度交互