1. 静态库 Mach-O Type = Static Library
平时我们用的第三方SDK基本上都是静态库,静态库的几个特点:
在App项目编译的时候会被拷贝一份编译到目标程序中,相当于将静态库嵌入了,所以得到的App二进制文件会变大。
在使用的时候,需要手动导入静态库所依赖的其他类库。(比如说某个SDK中使用到了CoreMotion.framework,在使用的时候需要手动导入。有的SDK需要link十几个系统库,这个时候非常恶心,只能一个一个手动加,这是静态库一个很大的不便之处。)
导入静态库的应用可以减少对外界的依赖,如果导入的是第三方动态库,动态库找不到的话应用就会崩掉,例如Linux上经常出现的lib not found。
静态库很大的一个优点是减少耦合性,因为静态库中是不可以包含其他静态库的,使用的时候要另外导入它的依赖库,最大限度的保证了每一个静态库都是独立的,不会重复引用。
2. 动态库 Mach-O Type = Dynamic Library
这个是我们最常用的一类库,使用频率最高的UIKit.framework和Fundation.framework都属于动态库,所有.dylib和.tbd结尾的都属于动态库。动态库的几个特点:
平时使用的系统库都放在iOS系统中,在你打包应用程序的时候这些库不会拷贝到你的程序中,当需要使用的时候会动态从iOS系统中加载它们,因为这个原因,动态库也被称作共享库。编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。
这些库是所有应用公用的,换一种说法就是节省了应用安装包的体积,这是区别静态库很重要的一个特点,因为静态库使用一次就要拷贝一次,非常浪费资源。
使用动态库的时候不需要再次link依赖库,即导即用,这个就厉害了。需要注意的是在导入第三方制作的动态库时,需要在Embedded Binaries中导入,不然调用时会报错:image not found。此时这个动态库会跟静态库一样被拷贝到目标程序中进行编译(会在App Bundle里生成一个Frameworks文件夹存放),苹果又把这种Framework叫做Embedded Framework,其中一个主要目的是为了App和App Extensions可以共用一份动态库framework而不用分别链接一份库的拷贝。
关于Embedded Framework,如果将动态库的工程文件直接引用进调用程序,如下图这样,则不用添加到Embedded里也能正常运行,不会报错image not found,原因未知,猜测这样组织XCode会将SubFramework做为静态库进行编译
关于Embedded Framework,还有有一点要注意,苹果文档说"If your containing app target links to an embedded framework, it must include the arm64 architecture or it will be rejected by the App Store."调试时只生成了模拟器指令集的动态framework,embedded之后运行程序肯能会有提示:This app could not be installed at this time导致无法运行,解决办法就是需要同时生成包含模拟器和真机的指令集的动态库
动态库在制作的时候可以直接包含静态库(embed framework),也能自动link所需要的依赖库,将包含的库直接链接进动态库的二进制文件
由于IOS APP的沙盒机制,我们自己制作的库,不管是静态库还是动态库,都只能在沙盒中访问,不同仅是静态库会被链接进App的可执行文件内,而动态库通过设置添加Embed Framework的方式在App沙盒中生成了一个Frameworks文件夹存放,因此比如沙盒里存在多个Excutable File(例如包含App Extension)共用这个framework,这时候可以用动态库,共享一份Framework,其他大多数情况用静态库和动态库区别就不大了
3.Umbrella Framework:包含子Framework的库
如上所述,因为静态库中是不可以包含其他第三方库的,而动态库可以包含第三方库,所以Umbrella Framework一般都需要设置为动态库,就可以包含子Framework了,网上有很多制作Umbrella Framework教程
4.因为苹果不建议使用Umbrella Framework,实际使用也可能会产生一些问题,可以用单独制作库(静态动态均可),使用时同时提供第三方依赖库的方式实现:
动态库与静态库的制作流程基本一样,包括头文件的暴露等,唯一不同的是Mach-O Type的设置。本节将介绍Xcode制作Framework的过程,本次制作的Framework静态库依赖其他第三方静态库(Framework和.a)。
1> 新建工程
新建Framework工程
这里要选Framework,如果选择右边的Static Library制作出来的是.a静态库。
2> 导入所有要打包的文件和其他第三方静态库
正常导入要打包的文件就可以了,在导入第三方静态库的时候要注意,不要选择添加到target中,如果添加进去要去target里面把第三方静态库删掉(只需导入,不要添加进target)
导入第三方静态库
导入第三方静态库之后再link依赖的系统库,像这样
link依赖库
注意上面的运行目标,因为我用的是Xcode8,最低支持到iOS8。
要打包的文件和第三方静态库全部导入完成
所有文件导入情况
3> 项目性质修改
把项目的membership需改为public,否则头文件暴露将会不正常
修改项目的membership
4> 暴露头文件
将头文件暴露出去,供外界使用,所有的编译文件都在Project中,需要右击添加到public里面
暴露头文件
5> 选择Mach-O的编译方式
这是最重要的一步,这一步决定我们制作出来的是静态库还是动态库,默认选择的是Dynamic Library,要手动选择Static Library
Mach-O 形式
6> 编译
如果你的依赖库里面有lib开头的dylib动态库,此时应该会报错
动态库链接报错
什么意思呢?大概就是没找到对应的库文件,因为tbd是苹果提供的新的动态库格式,之前都是dylib,不知道这里又抽什么风,下面解决问题。
7> tbd动态库报错修改
先把原来的.tbd删掉,然后再次添加,这个时候选择add other,在弹出的窗口中按快捷键shift + command + G 调出finder的前往窗口,输入/usr/lib,然后添加相应的dylib动态库
修改的动态库
替换完成之后重新编译项目,生成Framework(可在Product文件中右击在finder中显示找到)
8> 使用
新建一个文件夹,将制作好的静态库拷贝出来放进去,再将第三方静态库拷贝到相同的文件夹中,此时只要将这个文件夹提供给外界使用就可以了,这是我写的测试demo验证打包好的SDK是否可以正常使用
制作完成使用
至此我们已经完成了Framework中包含其他第三方静态库的制作。
如果需要制作动态库,只需要在第5步中将Mach-O的形式改为Dynamic Library就可以了,其他步骤一样
如果有问题请在留言区留言,或者邮件给我,互相交流学习!