为何需为iOS最终App目标显式添加动态框架的静态依赖?
初始项目结构
FinalApp (iOS App 目标) - ExcitingDynamic.framework (内部动态框架目标) - SomeOtherStatic.framework (第三方静态框架目标)
构建报错
FinalApp仅调用ExcitingDynamic.framework的公共接口,但构建时触发如下错误:
import ExcitingDynamic <- ERROR: Missing required module: SomeOtherStatic
临时解决方法
将SomeOtherStatic.framework添加为FinalApp的直接依赖,修改后项目结构如下:
FinalApp - ExcitingDynamic.framework - SomeOtherStatic.framework - SomeOtherStatic.framework
调整后构建恢复正常。
疑问
既然SomeOtherStatic已经链接到ExcitingDynamic,为什么还要显式添加到FinalApp目标?它不能被静态链接到动态框架中,让App自动识别吗?
注:不想将SomeOtherStatic嵌入ExcitingDynamic,因为苹果不推荐iOS这么做。
这是Swift模块依赖的编译特性导致的,核心原因如下:
静态框架的模块元数据未被打包进动态框架
当你把静态框架SomeOtherStatic链接到ExcitingDynamic时,只是将静态框架的二进制代码合并到了动态框架的二进制文件中,但SomeOtherStatic的模块元数据(比如.swiftmodule文件)并没有被整合到ExcitingDynamic的模块定义里。App编译时需要完整的依赖链模块信息
当FinalApp中执行import ExcitingDynamic时,Swift编译器会递归解析ExcitingDynamic的模块依赖——它会发现ExcitingDynamic的模块声明中依赖了SomeOtherStatic,此时就需要找到SomeOtherStatic的模块元数据。如果FinalApp的目标没有直接依赖SomeOtherStatic,编译器找不到对应的元数据文件,就会抛出“缺失必需模块”的错误。苹果禁止iOS动态框架嵌入静态框架的逻辑
iOS的动态框架是独立的可执行二进制文件,苹果要求它不能包含其他框架的完整模块(嵌入静态框架会导致符号重复、加载逻辑混乱等问题),因此只能让动态框架和App各自依赖静态框架,由App的构建流程统一处理静态框架的符号合并。
总结:静态框架的代码确实被合并进了动态框架,但模块元数据没有跟着走,App编译时必须能找到这个模块的元数据,所以必须将静态框架显式添加到App的依赖中。
内容的提问来源于stack exchange,提问作者ImShrey

