iOS 动态化热修复方案

2019-07-31 11:28:32 +08:00
 dKingbin

前言

iOS 热修复方案经过 JSPatch 事件后,也消停了很久。bang 神在《 JSPatch – 动态更新 iOS APP 》中曾提到,为了更符合 Apple 的规则,即《 Apple Developer Program License Agreement 》 里 3.3.2 提到的不可动态下发可执行代码。 JSPatch 特地绕了 js 的圈子,从而实现曲线救国、实现热更新的方案。但是事实证明了 Apple 对于这种方案也是不认可的,根本的原因还是在于 JSPath 做得太过极致--支持绝大部分的 OC/C 语法。

思考

既然 JSPatch 绕道 js 的方法,已经被 Apple 拒绝了,那么就再次回到原点,重新出发。新的框架或者新的方案我觉得至少有一个充分条件,就是不能太极致。 Objective-C 作为一种动态的语言,因此能够动态执行所有 OC 语法是正常的,Aspects 类似的框架也是被 Apple 认可的。至于是否需要运行所有的 C 函数,这个有待商榷。 第二个方面,则是放弃 javascript/lua 等类似语言作为更新的脚本,而是采用原生的 Objective-C 作为更新的脚本语言。

动态运行 C 函数

C 语言是没有反射机制的,作为一门编译型语言,在编译期间就已经生成机器码。因此如果要从字符串中获取到对应的函数指针,那么大概有两种方法:

第二种是目前 JSPatch 采用的办法,当然也被 Apple 警告了。dlsym 功能非常强悍,是获取函数指针的最优解。 第一种局限性非常大,但是也是最安全的方法,应该也是能被苹果所接受的一种方法。为什么这么说呢? 我们所追求的是能够动态运行所有的 OC 语法,加上部分 C 函数。因此在映射表中,只需要加上下面 runtime 常用的 C 函数映射, 我们就能够动态运行所有的 OC 语言。然后再自定义需要用到的 C 函数,基本上能够满足绝大部分热更新的需要,同时也能够被苹果所接受。

class_addMethod
NSSelectorFromString
objc_setAssociatedObject
objc_getAssociatedObject
class_getMethodImplementation
...

采用 Objective-C 作为更新的脚本语言

通过 flex/yacc,直接解析 Objective-C 语法,不再采取 js/lua 等脚本语言。

DynamicOC

经过上面的思考,在最近业余中做了DynamicOC的项目,百分百原生支持采用 Objective-C 作为更新的脚本语言。 当然动态运行 C 函数还是采用 dlsym 获取函数指针的办法,后面会逐步改为映射表的做法。

原理

DynamicOC使用 flex/yacc 进行词法解析和语法分析,转为一颗语法生成树 AST。 然后通过解析每个节点,从而执行相应的代码。因为采用的是 Objective-C 作为脚本语言,因此极容易适配。

功能特点

基本用法

动态执行 block

NSString* text = @" \
__block int result = 0;\
UIView* view = [[UIView alloc]init];\
void(^blk)(int value) = ^(int value){\
view.tag = value;\
};\
blk(1024);\
return view.tag;";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);

动态执行 C 函数

int echo(int value) {
return value;
}

NSString* text = @" \
[OCCfuntionHelper defineCFunction:@\"echo\" types:@\"int, int\"]; \
return echo(1024);";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);

动态添加 Property

NSString* text = @" \
[OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\
[OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\
NSString* key = @\"key\"; \
objc_setAssociatedObject(self, key, @(1024), 1);\
return objc_getAssociatedObject(self, key);";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);

已支持语法

TODO

参考链接

JSPatch – 动态更新 iOS APP

iOS 动态化的故事

Apple Developer Program License Agreement

滴滴 iOS 动态化方案 DynamicCocoa 的诞生与起航

5566 次点击
所在节点    iOS
5 条回复
loginbygoogle
2019-07-31 11:50:18 +08:00
我看你是想下架整改整改了
ooops
2019-07-31 12:29:39 +08:00
厉害厉害。不过你下发的还是可执行代码。“我们就能够动态运行所有的 OC 语言。然后再自定义需要用到的 C 函数,基本上能够满足绝大部分热更新的需要,同时也能够被苹果所接受。”不知道最后的结论是怎么得出来的。。
Sricecake
2019-07-31 18:50:38 +08:00
苹果目的是不希望有功能不经过审核就被用户使用,和你用什么技术无关。热更新和苹果审核天然是冲突的,不是你选择用那种技术方案就能解决的。
hanangellove
2019-07-31 22:07:52 +08:00
艸,为啥要用热更新。。。
技术说为了不用审核就可以改 bug,
产品说为了不用审核就可以改功能,
领导说要敏捷开发,快速迭代,
老板说我们外部竞争激烈,要快速适应新的市场环境。

。。。
程序员操碎了心,遂卒
xi_lin
2019-09-01 13:30:44 +08:00
应该移去 iDev 板块的。不过有试过这个能上架么?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/587808

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX