最近的工作是制作SDK,而在公司的SDK内部需要用到第三方的SDK,这就出现了Framework包含或依赖Framework的的情况。就把自己的一点看法记录下来。
名词解释:
包含:不需要对外暴露内部所使用的三方库
依赖:需要对外暴露内部使用的三方库
什么是静态库 (Static Library)
所谓静态库,或者说 .a 文件,就是一系列从源码编译的目标文件的集合。它是你的源码的实现所对应的二进制。配合上公共的 .h 文件,我们可以获取到 .a 中暴露的方法或者成员等。在最后编译 app 的时候.a 将被链接到最终的可执行文件中,之后每次都随着app的可执行二进制文件一同加载,你不能控制加载的方式和时机,所以称为静态库。
Framework也分为静态库和动态库。其中动态库又区分为系统的真正的动态库,自己制作的只能在APP内部使用的动态库(Cocoa Touch Framework)。
在 iOS 8 之前,iOS 只支持以静态库的方式来使用第三方的代码。
什么是动态库 (Dynamic Framework)
与静态相对应的当然是动态。我们每天使用的 iOS 系统的框架是以 .framework 结尾的,它们就是动态库。
Framework 其实是一个 bundle,或者说是一个特殊的文件夹。系统的 framework 是存在于系统内部,而不会打包进 app 中。app 启动的时候会检查所需要的动态框架是否已经加载。像 UIKit 之类的常用系统框架一般已经在内存中,就不需要再次加载,这可以保证 app 启动速度。相比静态库,framework 是自包含的,你不需要关心头文件位置等,使用起来很方便。
Cocoa Touch Framework
Apple 从 iOS 8 开始允许开发者有条件地创建和使用动态框架,这种框架叫做 Cocoa Touch Framework。
虽然同样是动态框架,但是和系统 framework 不同,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 时会被放到 app bundle 中,运行在沙盒里,而不是系统中。也就是说,不同的 app 就算使用了同样的 framework,但还是会有多份的框架被分别签名,打包和加载。
动态库、静态库的相互包含(Add to targets 也就是 Link Binary With Libraries)
.a静态库:
1 .a静态库内部可以包含.a静态库
2 .a静态库内部不可以包含.framework静态库
3 .a静态库内部不可以包含.framework动态库
.framework静态库
1 .framework静态库内部可以包含.a静态库
2 .framework静态库内部不可以包含.framework静态库
3 .framework静态库内部不可以包含.framework动态库
.framework动态库
1 .framework动态库内部可以包含.a静态库
2 .framework动态库内部可以包含.framework静态库
3 .framework动态库内部不可以包含.framework动态库
动态库、静态库的相互依赖(Add to targets 不添加)
以上不能包含的都可以使用依赖来解决。
.a静态库:
1、可以引用.framework静态库,使用时需要两者都添加到项目。
1、可以引用.framework动态库,使用时需要两者都添加到项目。
.framework静态库
1、可以依赖.a静态库,使用时需要两者都添加到项目。
2、可以依赖.framework静态库,使用时需要两者都添加到项目。
3、可以依赖.framework动态库,使用时需要两者都添加到项目。
.framework动态库
1、引用.a静态库时,编译报错。
2、引用.framework静态库时,可以编译通过,但是运行闪退。
3、可以引用.framework动态库,使用时需要两者都添加到项目。
动态库、静态库相互包含或依赖的解决方案
如果需要对外提供一个SDK D,D内部还需要用到A、B、C三个库,则可以这样设计。
第一种:
A、B、C都是静态库.a D是静态库.framework
第二种:
A、B、C都是静态库.framework D是动态库.framework
第三种:
A是静态库.a B是静态库.framework C是静态库.framework D是动态库.framework
如果要求B是动态库.framework,则:
A:静态库.a
B:动态库.framework
C:静态库.framework
D:动态库.framework
B包含A,C依赖B,D包含C,最终只需要对外提供D,B这两个动态库就行了。
注意:A、B、C、D之间的关系。包含也就是Add to targets,依赖也就是不Add to targets。
如果静态库多次被copy,则会出现提示库使用重复的警告,而且无法通过xcodebuild打包成功。这个时候就需要检查 add to target的使用是否正确。
可以通过file命令检查当前库是动态库还是静态库:
cd /Users/leo/Desktop/TXLiteAVSDK_TRTC.framework
file TXLiteAVSDK_TRTC
知道当前库为静态库(current ar archive)
TXLiteAVSDK_TRTC: Mach-O universal binary with 4 architectures: [arm_v7:current ar archive] [i386] [x86_64] [arm64]
TXLiteAVSDK_TRTC (for architecture armv7): current ar archive
TXLiteAVSDK_TRTC (for architecture i386): current ar archive
TXLiteAVSDK_TRTC (for architecture x86_64): current ar archive
TXLiteAVSDK_TRTC (for architecture arm64): current ar archive
如果是动态库(Mach-O dynamically),显示如下:
ImSDK: Mach-O universal binary with 3 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm_v7] [arm64]
ImSDK (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
ImSDK (for architecture armv7): Mach-O dynamically linked shared library arm_v7
ImSDK (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
暴露动态库A里面包含的静态库B
动态库A不用修改,只需要在使用到B的外部项目中再引入一次B即可。
这篇文章写的挺好:
https://www.jianshu.com/p/fb5083f2c0d2