不少状况下,已经在 AppStore 上线的应用须要紧急缺陷修复,此时便须要使用某些技术手段,使应用程序可以动态下载补丁,进行缺陷修复。css
迄今为止,脚本语言中运行速度最快的是 Lua。Lua 语言由巴西里约热内卢天主教大学的 Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo 于 1993 年开发的。其最初的设计目的是提供一个方便嵌入到应用程序中得脚本语言。Lua 语言彻底使用 ANSI C 实现,其设计精巧,代码优美。Lua 的解释器总共在 200k 大小,并且运行速度大约是 C 语言的 1/5,语法比较简单,即便不是专业的编程人员也容易掌握。html
2003 年,随着暴雪的大型在线网络游戏 《魔兽世界》的发布,Lua 逐渐被人们所知(《魔兽世界》的插件系统就是使用 Lua 开发), Lua 逐渐在游戏界流行起来。如今国内几乎大部分游戏策划都使用 Lua 语言来进行数值或者关卡的设计。编程
因为 Lua 编程简单,运行速度快,在 iOS 上, 一个支持使用 Lua 语言编写 iOS 应用的项目 Wax 诞生了。Wax 项目容许用户使用 Lua 语言调动苹果 iOS SDK 的功能,进行应用程序的开发。安全
Wax Patch 项目是由 Wax 项目衍生而来,Wax patch 不只仅容许用户使用 Lua 调用 iOS SDK 和应用程序内部的 API, 并且使用了 Objective-C runtime 的 class_replaceMethod 调用替换应用程序内部由 Objective-C 编写的类方法,从而达到功能微调或者缺陷修复的目的。服务器
Wax/WaxPatch 主要特色:
网络
● 全部 Objective-C 调用接口构建在 Objective-C runtime 之上,因此其调用 Objective-C 的 API 方式很是方便,不像调用 C/C++ 哪样,必须先为 Lua 编写调用接口(有些技术能够帮助 Lua 调用 C/C++ 编写的动态库而没必要事先编写调用接口, 可是在 iOS 上不能调用应用程序本身编写的 API)。
app
● 对于 Objective-C 和 Lua 之间的数据类型转换进行了封装,使得开发者没必要关心 Lua 和 Objective-C 的数据类型转换,方便开发。编辑器
Objectvie-C 语言的特性和实现机制决定了任何其余脚本语言对其进行调用都很方便。主要缘由在于 Objective-C runtime 提供了对于 类/对象 等 OC 类型的反射和自省机制。函数
相关的 API 以下:测试
typedefstruct objc_class *Class;
structobjc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedefstruct objc_object *id;
typedefstruct objc_selector *SEL;
typedefid (*IMP)(id, SEL, ...);
SELsel_getUid(const char *str);
constchar *object_getClassName(id obj);
Classobjc_getClass(const char *name);
Methodclass_getInstanceMethod(Class cls, SEL name);
Methodclass_getClassMethod(Class cls, SEL name);
IMPclass_getMethodImplementation(Class cls, SEL name);
IMPclass_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
藉由以上 API,则能够经过字符串来动态调用 Objective-C 的类和对象的方法。
Wax/WaxPatch 调用 Objective-C 并非简单得对 Objective-C runtime 的 API 进行 1 对 1 得封装,而是把全部的 Objective-C 的对象\类\函数\等抽象成一个 WaxInstance,对 WaxInstance 进行操做。而 WaxPatch 则对 WaxInstance 的元表的 __newindex 属性进行改写,调用 class_replaceMethod 方法改写父类的函数实现,使用 forwardInvocation 机制把针对父类的调用方法转发到 Lua 改写的类方法里面。
咱们在一些项目中使用 WaxPatch 来实现热更新机制,主要的流程以下所示。
整个流程遵循如下原则:
● 简单有效,避免复杂逻辑。整个补丁包是全部补丁的全量包而不是增量包。
● 安全性要有保证。发布版的补丁包是须要通过加密的,避免被恶意篡改。
● 正确性。在打补丁的过程当中,一旦出现错误,则马上退出补丁流程,避免对原应用程序的流程产生致命的损坏。
├── 20150701_01
│ ├──LoadPatchViewController.lua
│ └──init.lua
├── 20150703_01
│ ├──LTMoviePlayerViewController.lua
│ ├──LTPlayControlCenterView.lua
│ └──init.lua
├── LuaPatchManager.lua
└── letv_hotpatch_mapping.lua
① letvPatchManager.lua :补丁管理和执行文件,经过对客户端版本号和 letv_hotpatch_mapping.ua 文件判断补丁是否应该用于客户端。
② letv_hotpatch_mapping.lua:补丁索引文件,记录补丁适用于那个客户端版本。
③ 20150701_01:补丁包分包,为了方便补丁包管理,对单个补丁文件进行分组。
④ 20150701_01/init.lua:补丁分组执行文件。
⑤ 20150701_01/xxxx.lua:功能性的补丁。
整个方案主要由如下部分组成:
● 补丁包管理器:集成在客户端内部,使用 Objective-C 编写,负责从服务器下载补丁包,并解压到客户端的沙盒中。
● 补丁包:见上文。
● 补丁打包器:负责把全部明文补丁进行加密,并打包成 zip 格式供客户端下载。
block 调用和实现
WaxPatch 对于 Objective-C 的 block 支持不够完备,虽然有一些 WaxPatch 的衍生版本增长了一些 block 的支持,可是并不能令咱们满意,尤为是 block 的参数支持上。对此。咱们本身增长了 WaxPatch 对 block 的支持,作到了对 block 的可变参数的支持。
安全性解决方案
因为 WaxPatch 能够作到对全部 Objective-C 的 API 修改(包括系统的和客户端内部的)。因此理论上来讲,一个非法的 lua 补丁能够修改客户端全部的流程和功能,以至于对最终用户的信息形成伤害。
为了保证客户端功能和流程的安全性,在发布的补丁包中,全部的 Lua 补丁源码都由秘钥进行加密。在客户端方面,咱们针对 Lua 的解释器进行修改,使用公钥进行解密和验证码,避免非法的 Lua 补丁文件被执行。
与 WaxPatch 方案相同的另一个方案是 JSPatch。JSPatch 使用系统内置的 Javascript 解释器来动态 Javascript 代码,达到与 WaxPatch 一样的目的。其原理与 WaxPatch 基本相同。
通过调查,JSPatch 与 WaxPatch 相比,有一些固有的缺点没法解决:
① 在 iOS6.0 系统上,Apple 并无开放 JavascriptCore 引擎,须要本身内置 JS 引擎,增长客户端的体积。
② 因为 JSPatch 使用系统的 JavascriptCore 引擎,咱们没法去验证 Javascript 补丁的合法性和有效性,对客户端带来了很大的安全隐患。
以上缘由决定使用 WaxPatch 的方案而不是 JSPatch 的方案。
软件开发的正途应该是:以增强代码质量和严格的测试来控制客户端质量。虽然 WaxPatch 能够作到对线上应用程序的缺陷进行快速修复,可是这种手段永远只能做为最后的一个防线,而不能过于依赖它。
转自http://www.wtoutiao.com/p/w4d1Fz.html,谢谢原做者。