402's Dojo

JSPatch实战系列 - JSPatch Convertor初探

iOS平台热更新机制一直是iOS开发者感兴趣的话题,随着苹果对开发者公开更多的API,热更新方案也日趋完善。基于Lua语言的Wax逐渐被基于JS语言的JSPatch所取代(有关两种方案的对比参见我的一篇拙文JSPatch与Wax对比分析)。近日@bang神带来了又一个惊艳之作:Objective-C到JSPatch脚本的自动转换工具:JSPatch Convertor
先用一句话介绍一下:JSPatch Convertor是Objective-C to JSPatch脚本以方法为单元的代码转换工具。之所以强调以方法为单元是因为这个工具是为JSPatch开发的,目前的支持的语法仅限于实现OC方法转换为JS方法,如果要实现整个项目的迁移,需要对当前的实现继续扩展,但是@bang神给了我们非常好的思路和一个绝佳的开始。
JSPatch Convertor实现方式可以概括成如下:

  1. 先通过ANTLR (ANother Tool for Language Recognition)将OC代码转换成AST语法树;
  2. 遍历语法树,生成JPContext(语法解析单元)链;
  3. 调用JPContext链上每个单元的parse()方法,构造OC代码。
    有关详细的实现原理没办法写得比原作者更好了,在实现过程中有几个关键点:ANTLR、JPContext(中间数据结构),可以再介绍一下:

ANTLR

ANTLR 是一个 LL(k) 语法分析器——也就是说,它遵循自顶向下的语法分析算法,具有从左至右地分析输入流的先行分析 k 标记。
Antlr(ANother Tool for Language Recognition)是一个工具,它为我们构造自己的识别器(recognizers)、编译器(compiler)和转换器(translators)提供了一个基础。通过定义自己的语言规则,Antlr可以为我们生成相应的语言解析器,可以在官方文档上找到生成方法。

设计的巧妙之处 - JPContext(中间数据结构)

Antlr语法树生成器在解析OC语法的过程中根据语法的不同(如方法声明、方法调用、block)返回不同的回调函数,对语法解析构建JSPatch脚本的过程正式在这些回调中完成的。
语法树分析过程是上下文相关的,同样一个方法调用在函数中、在block中解析的方式都不同。为了解耦独立这种相关性,JSPatch Convertor将每句解析的上下文环境保存在JPContext和其子类中,也就是所说的中间数据结构,通过这样一种中间数据结构在语法树解析的时候保存上下文环境,进而允许在解析全部完成之后再进行JSPatch代码的拼装,实现了原代码解析和新代码构建的分离。
构思精巧,面向对象和数据结构应用的恰到好处。

JSPatch Convertor的使用

JSPatch Convertor的github项目是一个完整的站点:

只需要部署到服务器上即可使用。JSPatch Convertor @ 402v是我为了以后自己做扩展方便搭建的一个原站点的镜像站。在左边输入OC的原始方法,点击convert就可以转换为JSPatch的脚本代码

由于语法树解析的关系JSPatch的方法顺序是倒着的,不支持变量声明,#pragma mark -等语法。下面是官网给出的一些JSPatch Convertor目前不支持的语法。

JSPatch-Convertor的局限

  1. Macro / constant variable / Enum
  2. C function calling
  3. GCD functions
  4. Pointer / Struct
  5. Getting / Setting private variable

当然,如果要做类级别甚至工程级别的转换,局限还不止这些,但是@bang神给了我们非常好的思路和一个绝佳的开始。同时鉴于JSPatch处理函数的映射方式,如果做工程级别转换对程序的执行效率和稳定性也是一个很大的挑战,相比之下期待@facebook团队接下来会有一个React Native-Convertor之类的东西出来。

NB的程序员与程序

最初见到JSPatch框架时原以为@bang神只是因为iOS7开放新的JSCore Framework来玩一把,没想到@bang神是真的很认真的当个系统来做,JSPatch的不断完善,而后又推出了JSPatchSDK和开发平台,到现在竟然连转换工具JSPatch Convertor都做了,真正形成了iOS热更新的体系,佩服至于也略感惭愧。

  1. 再次推荐bang神的blog,现在第一篇就是介绍JSPatch Convertor的,如果你也能把自己写的程序解释的这样清楚,那么也可以写出这样NB的程序;
  2. 当你开始一项工作时,什么都不要想,直接去做;
  3. 当你完成一项工作时,努力去想,接下来还有哪些值得做。

What we can do next?

  1. 宏定义的预读取
  2. C方法的自动转换
  3. 转换后代码执行的效率测试

评论