参考链接

JSPatch - 动态更新iOS APP: http://blog.cnbang.net/works/2767/

JSPatch实现原理详解: http://blog.cnbang.net/tech/2808/

JSPatch实现原理详解<二>: http://blog.cnbang.net/tech/2855/

Github地址: https://github.com/bang590/JSPatch


以下为引用……

用途

在项目中引入JSPatch,可以在发现bug时下发JS脚本补丁,替换原生方法,在不更新APP的情况下即时修复bug。

原理

JSPatch用iOS内置的JavaScriptCore.framework作为JS引擎,通过Objective-C Runtime,从JS传递要调用的类名函数名到Objective-C,再使用NSInvocation动态调用对应的OC方法。

方案对比

目前已经有一些方案可以实现动态打补丁,例如WaxPatch,可以用Lua调用OC方法,相对于WaxPatch,JSPatch的优势是:

1. JS语言
  • JS比Lua在应用开发领域有更广泛的应用,目前前端开发和终端开发有融合的趋势,作为扩展的脚本语言,JS是不二之选。
2. 符合Apple规则
  • JSPatch更符合Apple的规则。iOS Developer Program License Agreement里3.3.2提到不可动态下发可执行代码,但通过苹果JavaScriptCore.framework或WebKit执行的代码除外,JS正是通过JavaScriptCore.framework执行的。
3. 小巧
  • 使用系统内置的JavaScriptCore.framework,无需内嵌脚本引擎,体积小巧。
4. 支持block
  • wax在几年前就停止了开发和维护,不支持Objective-C里block跟Lua程序的互传,虽然一些第三方已经实现block,但使用时参数上也有比较多的限制。

相对于WaxPatch,JSPatch劣势在于不支持iOS6,因为需要引入JavaScriptCore.framework。另外目前内存的使用上会高于wax,持续改进中。

风险

JSPatch让脚本语言获得调用所有原生OC方法的能力,不像web前端把能力局限在浏览器,使用上会有一些安全风险:

  1. 若在网络传输过程中下发明文JS,可能会被中间人篡改JS脚本,执行任意方法,盗取APP里的相关信息。可以对传输过程进行加密,或用直接使用https解决。
  2. 若下载完后的JS保存在本地没有加密,在未越狱的机器上用户也可以手动替换或篡改脚本。这点危害没有第一点大,因为操作者是手机拥有者,不存在APP内相关信息被盗用的风险。若要避免用户修改代码影响APP运行,可以选择简单的加密存储。

个人看法

仅用于紧急修复bug

JSPatch的确是江湖救急的一个好方案。

但如果想用它去新增一个功能模块使APP进行热更新,总的说来代价不会比迭代版本低

因此它不应用于开发新功能,只能用于修复线上bug

规范版本控制

version1出现bug,发布patch1作修复,此后version1都会加载patch1,直到version1的用户比例足够小的时候,才能考虑是否让patch1退役。

但version2必须在OC代码中修正bug,并且不会加载patch1。

当version2也发现一个bug时,发布patch2;若此bug在version1也存在,则需要将patch2的相应修改merge到patch1,使得version1的用户也能够正常使用。

也就是说,一个版本,最多对应一个补丁js。

于是,用户对在线js发起下载请求的时候,可以使用动态生成的方式,以当前版本号作为参数,每个版本号实际上都有它对应的patchs,规则在服务端处理好即可。

快速修复

出现重大bug时,往往需要快速修复。这时候,就比较考验变成功底了。使用JSPatch去修正的流程为:

编写并调试OC代码 -> OC代码测试无误,改写成js代码 -> 对补丁js进行测试,确定能够解决线上版本bug,并且无新bug时,才能发布patch

OC开发人员是否未必熟悉js,因此在步骤二可以想象一些优化方案,理想状态下是自行编写相应的正则转换方法,使这一步快速并且可靠。

注意

  • 不支持iOS6,所幸iOS6的用户比例已经足够小了
  • 文中陈述的安全风险
  • 关于动态代码的错误调试还有待研究