编程技术记录

世界你好!

背景

​ 本文将介绍一种在有源码的情况下,新老版本静态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编译插件,增加命名空间语法支持,从根本上解决问题。不过,尚未完成。。。

https://github.com/kylesluder/objc-namespaces

© Beli. All Rights Reserved.