背景
本文将介绍一种在有源码的情况下,新老版本静态SDK共存于同一应用的方法实现。
静态SDK升级并上线后,可能会发现新版本SDK有问题而老版本SDK没有问题的现象,这时对于已经升级的应用将无法直接回退到老版本SDK,除非一开始就新老版本SDK同时存在于这个应用中。
对于Objiective-C这种没有命名空间的语言,当一份代码构建出两个静态库,且两个静态库同时链接于同一个应用时(同一个应用同时链接这个两个静态库),那么将会发生符号冲突问题—-符号重定义(duplicate symbol);而解决符号重定义的办法就是将符号重命名,当然删除符号也可以—-不过这样可能引起符号为定义错误。
就Objiective-C而言,符号重命名需要修改源码。对于静态SDK工程来说,第一步是需要先将类名、函数名、全局变量名这些符号列举出来,然后逐一添加前缀或者后缀,对于影响业务逻辑的地方还需要斟酌修改,特别是Objiective-C的运行时反射更要注意。例如像NSClassFromString,相关代码添加前缀或者后缀要仔细
。
模块化拆分
这步骤不是必须,但是强烈推荐的。
就双静态SDK共存这事来看,模块化拆分的唯一目的是减少需要修改的符号数量:例如,通常情况下像AFNetworking这种工具库是没有必要添加前缀或者后缀的。
所以,拆分的唯一原则:将长期不修改的代码拆分出来,这部分可以作为双SDK的公共库。
导出符号列表
常见的方法是使用nm
工具,可以导出SDK里的符号列表。也可采用分析linkmap
文件的方式,导出SDK里的符号列表。
需要导出的符号有:
-
类名
-
函数名—非类所属
-
全局变量名
导出的全局变量名如果是静态变量名,一般不需要添加前缀或者后缀。不一般的情况,非静态全局变量引用了静态变量,这时就要处理下。
添加前缀或者后缀
这里推荐使用预编译宏技术,定义一个宏并使用##
连接符
#define SUFX (x) x##_我是后缀
// 类
@interface SUFX(MyClass) ---> @interface MyClass_我是后缀
[SUFX(MyClass) method] ---> [MyClass_我是后缀 method]
// 函数
void SUFX(MyFunc) ---> void MyFunc_我是后缀
//变量
int SUFX(MyVar) ---> int MyVar_我是后缀
给Objective-C添加命名空间?
最后,介绍下llvm编译插件,增加命名空间语法支持,从根本上解决问题。不过,尚未完成。。。