A. 主项目使用动态库TestFramework
A1. TestFramework
通过Pod依赖三方库(dynamic framework)
现象
编译不报错,运行时报错 dyld[30339]: Library not loaded: @rpath/MBProgressHUD.framework/MBProgressHUD Referenced from: <9FB255F3-CED4-32E5-A9EF-10E473D3BAF6>
根本原因
通过pod
依赖的三方动态库无法被动态库TestFramework
合并,导致主项目使用时报错;
- 编译/链接阶段,主项目只需要能找到
TestFramework.framework
里声明的符号即可; TestFramework.framework
的二进制里,引用了MB/MJ
的符号,但这些符号在TestFramework
的链接阶段已经解决(因为TestFramework
已经链接了MB/MJ
)。- 主项目编译时不需要直接看到 MB/MJ 的实现,只要
TestFramework
能链接通过,主项目就能编译通过。
解决办法
1、通过构建私有库并且在podspec
中配置对MBProgressHUD
的依赖,来保证主项目可以正常引用动态库MBProgressHUD
; 2、直接把MBProgressHUD
和MBProgressHUD
这两个动态库和TestFramework
一起提供给主项目,主项目进行embed &sign in
后即可
A2.TestFramework
通过Pod
依赖三方库(static framework)
现象
主项目可以正常编译运行
根本原因
这主要是因为通过pod
依赖的三方静态库(framework类型
)被动态库TestFramework
所吸收,导致主项目只需要引用动态库TestFramework
本身即可,
A3. TestFramework
通过Pod
依赖三方库(static .a
)
现象
主项目可以正常编译运行
根本原因
这主要是因为通过pod
依赖的三方静态库(.a类型
)被动态库TestFramework
所吸收,导致主项目只需要引用动态库TestFramework
本身即可,
B. 主项目使用静态库TestFramework
B1. TestFramework
通过 Pod
依赖三方库(static.a)
现象
主项目编译不过,经典报错Undefined symbol: _OBJC_CLASS_$_MBProgressHUD
根本原因
静态框架(Static Framework)
在构建时是可以将依赖的静态库代码合并进来的, 具体逻辑是 1、如果是直接链接(在 Link Binary With Libraries
中直接添加.a
文件):静态框架会将依赖代码合并进来,这是正常的静态链接行为,此时不需要额外操作,主项目依赖TestFramework
可以正常编译运行 2、如果是通过 CocoaPods
间接依赖:CocoaPods
创建的只是一个"依赖声明",实际的代码合并被推迟到最终应用构建时,这是 CocoaPods
的设计选择,不是静态框架的限制
解决办法
1、通过CocoaPods
间接依赖的.a可以通过runscript脚本实现合并.a的符号到framework中
bash
FRAMEWORK_BINARY="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"
MBHUD_LIB="${BUILT_PRODUCTS_DIR}/MBProgressHUD/libMBProgressHUD.a"
MJEXT_LIB="${BUILT_PRODUCTS_DIR}/MJExtension/libMJExtension.a"
# 使用 libtool 直接合并静态库
libtool -static -o "${FRAMEWORK_BINARY}" "${FRAMEWORK_BINARY}" "${MBHUD_LIB}" "${MJEXT_LIB}"
2、修改TestFramework
的link binary with library
,将pod
生成产物MBProgressHUD.a
和MJExtension.a
加入进去,可能会提示
File is already being linked. Linking "MBProgressHUD.framework" more than once is not supported. To use the same framework for multiple platforms, use an XCFramework.
选择add anyway
即可
.a
文件就是一堆对象文件(.o)
打包在一起的"压缩包";Xcode/ld
链接器在链接时会递归展开所有 .a
文件,把里面的对象文件合并进最终产物;只要你在 Link Binary With Libraries
里加了 .a
,它的内容就会被"吸收"进你的 framework
或可执行文件。
B2. TestFramework
通过Pod依赖三方库(static framework)
现象
主项目编译不过,经典报错Undefined symbol: _OBJC_CLASS_$_MBProgressHUD
根本原因
静态框架(Static Framework)
在构建时是可以将依赖的静态库代码合并进来的, 具体逻辑是通过 CocoaPods
间接依赖的framework
:CocoaPods
创建的只是一个"依赖声明",实际的代码合并被推迟到最终应用构建时,这是 CocoaPods
的设计选择,不是静态框架的限制
解决办法使用脚本进行合并
bash
#!/bin/bash
# 合并静态框架依赖
FRAMEWORK_BINARY="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"
MBHUD_FRAMEWORK="${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework/MBProgressHUD"
MJEXT_FRAMEWORK="${BUILT_PRODUCTS_DIR}/MJExtension/MJExtension.framework/MJExtension"
# 使用 libtool 合并静态框架
libtool -static -o "${FRAMEWORK_BINARY}" "${FRAMEWORK_BINARY}" "${MBHUD_FRAMEWORK}" "${MJEXT_FRAMEWORK}"
这里不能使用修改TestFramework的link binary with library
的方式,因为static framework
其实是一个目录结构,里面有 Headers、Modules、Info.plist
,还有一个二进制文件(通常是静态库格式)。但 Xcode
在链接时不会递归处理 framework
里的依赖,它只会把你当前 target
的源文件和你直接加的 .a
文件合并。framework
只是目录结构的封装,Xcode 只会把 framework 作为一个整体链接,不会像处理 .a 那样递归合并里面的内容。我猜主要是Xcode 设计时主要是为动态库(dynamic framework)
服务的,动态库的依赖是运行时解决的; .a
是静态链接的"原生食材",Xcode
会把它"煮进锅里";static framework
是"盒饭",Xcode
只会把盒饭放在桌上,不会拆开盒饭再煮一遍。