apple frameworks
动态库 & 静态库,若单独输出并接入主工程,逻辑倒很清晰。如果牵涉到多个 framework 不同类型并且相互依赖,会增加不少复杂度。
以下说明中,动态库使用 DFramework 表示,静态库使用 SFramework 表示。
1 framework
仅需要提供 1 个 framework,直接提供 DFramework 即可。DFramework 优先,必要的时候再提供 SFramework
n framework
因为代码结构分组,可能需要提供多个 framework:
- DFramework 优先,能不提供 SFramework 就不要提供
- 有 n 个 DFramework 就提供 n 个。相互之间做好依赖文档,App 需要根据依赖文档 flat 平铺接入所有需要的 DFramework。
- 如果 b DFramework 仅仅被 a DFramework 依赖,可以将 b 打入 a DFramework 的
frameworks
文件夹中,通过embed
实现。- 这样就可以不再文档中说明 b DFramework 的存在,对外界透明。
- 这种方案,最终的 app 中 framework 不是 flat 平铺的,而是具有层级结构,如 :App - a DFramework - b DFramework
- 如果 b DFramework 同时被 m DFramework 和 n DFramework 依赖,不能将 b 隐藏(打入 m 和 n 中)。
- 否则,App 集成 m 和 n 的时候,b 会出现多份。如果 b 的版本不一样,将按照打包顺序只使用其中一个。
- 如果提供 SFramework,则将所有的 framework 做成依赖,输出一份 SFramework 即可。
- 如果有按需接入的场景,按按照场景输出 n 个 SFramework。
依赖开源库
一般这种场景是因为开发 framework 的同时,又使用了开源的库。这个时候如何处理开源库是个问题(开源库一般都是 源码 提供的,不讨论 闭源包 提供方式,这个和上面的场景一致)。
由于 apple 的 Swift Package Manager 三方库管理的介入,一个 module 在最终的 app 中到底是 dymanic 还是 static,已经不可控了。SPM 会自行管理,不像 cocoapods 的时候我们可以自行控制。
如果是源码提供者,可以增加 dymanic /static 约束。但很多源码都不会提供这个选项,而是让 SPM 自行管理采用哪一个。
在这种场景下,开发的 framework 如果对开源库有依赖,就必须考虑是否【去开源】事宜了。
另外,除了自己使用开源库,App 主工程开发者,可能也需要使用同一个开源库,这时候还会出现【版本不一致问题】。
以下场景,假设有 T 开源代码需要使用:
不封装,让外界接入
framework 需要依赖 T
- 如果不是强依赖,在 xcode 中使用
-weak_framework
进行标记,这样业务也可以不接入,相当于默认不使用这个功能。 - 如果是强依赖,并且在 文档 中说明业务需要接入 x 的具体版本范围。不接入无法编译或者 app 启动闪退。
封装,外界无感
第一步就是需要对 T 进行【模块隔离】,否则外界也接入 T 的时候,App 主工程和我们提供的 framework 同时有 T 代码,会有问题。
虽然 xcode 在编译连接的时候,会处理好这个问题,使得同一份代码尽量在 app 中仅保留一份。
但如果开发人员使用不恰当或者配置错误,很可能导致出现两份 T 源码在项目中。
这个时候如果版本还不兼容,就会有非常大的调试和异常隐患。
模块隔离方案:修改 Product Name,将 T 变成 TT 模块
然后,还需要考虑将 TT 变成静态库还是动态库:
静态库:
这是完全去开源的方案。变成静态库后,TT 源码将打入 framework 二进制中一起提供。因为模块隔离,外部也无法调用和感知。
- 通过对 framework 二进制字符表进行分析,还是能够看到 T 的踪迹。
- 如果不做模块隔离,也能成功。主 app 也使用 T 模块的时候,链接的时候将自动保留 1 份静态代码。有版本差异的话,出现异常问题将非常难以排查。
动态库:
使用动态库的话,如前面【需要提供多个 framework】所描述的,有两种方案:
- TT 可以提供给业务,让业务自行接入。是 flat 平铺 结构。
- 也可以内嵌到 m framework 的 frameworks 文件夹中专门供 m framework 使用。是 内嵌 结构。
- 如果不做模块隔离,也可以内嵌。但主 app 可能也使用了 T 模块,使得同一个工程包含 2 个版本的 T 模块,运行的时候按照 xcode 编译顺序,只有一份被使用。有版本差异的话,出现异常问题将非常难以排查。