写在前面
过程有点长,但是比较细节,看官各取所需。
创建静态库工程
可以先了解iOS库 .a与.framework区别,静态库可以分为.a和.framework类型的的文件。Xcode创建的静态库工程,默认编译后获得的静态库文件是.a类型的。
Xcode(9.1)创建分为动态库工程和静态库工程:
而我们又需要.framework类型的(而对bundle类型的TARGETS进行一些设置,即可得到一个输出framework文件的工程)具体操作如下:
1)选择上图的静态库,创建一个静态库工程:
2)因为编译生成.a文件,所以删除默认的TRAGETS,后面重新添加一个bundle类型的即可。
3)有些教程说,在Product->Scheme->Manage Schemes中,需要删除关联的build项(其实只要新建的TARGETS的名称相同,是不用删除的,只要新建了,就会重新关联上):
4)删除工程文件:
5)这个时候可以新建一个bundle类型的TARGETS了(注意此处是bundle是属于macOS类型的,后续需要一些设置):
上面说到,新建的时候使用与工程同名的来创建新的TARGETS,即可不用删除默认的build关联项:
6)创建完毕,可以看出,bundle在默认情况下,是适用于Mac OS的:
因此需要我们对这个bundle类型的TARGETS做一些设置:
创建bundle类型TARGETS的一些设置:
参考:ios 制作自已的framework
1)
Base SDK:Lstest iOS(iOS XX.XX)
2)指令集设置
Architectures:Standard architectures - $(ARCHS_STANDARD)默认之外,添加一个:armv7s
Valid Architectures: armv7 armv7s arm64
具体原因点这里
3)Dead Code Stripping用于删除对象文件中不需要加载的符号,减小二进制文件大小(此处为何关闭,我也不知道原因,哪位大神知道的告知一声)
Dead Code Stripping:NO
4)关联标准库(此处关闭,我也不知道原因,哪位大神知道的告知一声)
Link with Standard Libraries:NO
5)库类型
可参考:浅谈 SDK 开发(一)五种 Mach-O 类型的凛冬之战
Mac-O Type:Relocatable Object File
6)
在 Packaging 中,将 “Wrapper Extention” 改为“framework”
7)
info文件将 “Bundle OS Type Code” 改为 “FMWK”(Framework 的意思)
8)设置SDK支持的最低系统
Build Settings -> Deployment -> iOS Deployment Target 修改具体参数
也可在 General -> Deployment Info -> Deployment Target 处设置,两处设置等效
至此,相关设置完成,即可选择相应环境,Cmd+B 进行编译,以获得framework
打开StaticLibObject.framework所在的文件夹,发现这个:
编译后的framework包,是真机环境和模拟器分开的,其实是因为二者所支持的指令集不同,具体得看你的Architectures设置,必要的时候,可以使用lipo命令来合并两个文件成一个文件,使其即支持真机,又支持模拟器。
我们查看,或者合并的文件就是这里面的文件:
查看真机的(请看我上面的关于Architectures的设置):
$ lipo -info WxxStaticLibFramework
Architectures in the fat file: WxxStaticLibFramework are: armv7 armv7s arm64
查看模拟器的:
$ lipo -info WxxStaticLibFramework
Non-fat file: WxxStaticLibFramework is architecture: x86_64
修改下模拟器的文件名,将其扔进真机的文件夹,执行合并命令
注意咯:最好合并输出的文件与原来的保持名字一致,替换掉原来的文件即可。否则framework中会找不到这个文件!!!(修改了名字还能关联的,有好的办法请告诉我)
lipo -create 模拟器库 真机库 -output 最终库
$ lipo -create StaticLibObject StaticLibObjectSimulator -output StaticLibLastFramework
查看最终合并的所支持的指令集:
lipo -info StaticLibLastFramework
查询结果:
Architectures in the fat file: StaticLibLastFramework are: x86_64 armv7 armv7s arm64
StaticLibLastFramework已经可以同时用于真机和模拟器了!可是这种方式有点麻烦,每次重新编译,都需要重新合并文件,据说还可以用脚本的方式来合并,待我研究后再补充,这里先占个坑。
framework的使用
framework的使用,无非就是对外暴露.h文件,.h文件中有写好的被人使用的方法。这里抛砖引玉。下面具体说明:
1)新建对外文件,并提供方法 +(void)staticLibSDKTest;
内部方法实现:
+(void)staticLibSDKTest{
NSLog(@"static lib sdk test method");
}
2)暴露头文件
Build Phases -> + ->New Header Phase
注意:添加完默认是归类到Project中,将需要暴露的.h文件,手动拖进Public中即可。
重新编译,即可发现,头文件已经对外暴露了:
3)创建一个普通工程StaticLibObjectDemo
来测试刚刚创建的framework,跑这个工程的时候,注意真机和模拟器的区别!framework的指令集和工程的运行环境要对上!当然,合并执行真机和执行文件的另当别论了。
引入framework的操作这里无需赘叙了:
4)在使用的地方 #import
#import <StaticLibObject/StaticLibSDK.h>
5)调用StaticLibSDK.h中的方法
[StaticLibSDK staticLibSDKTest];
很开心的快捷键Cmd+R,发现报错了:
具体错误:framework not found StaticLibObject
果然,原先的文件被我删除了,留下的可执行文件是支持模拟器和真机的通用文件StaticLibLastFramework
,连文件名都不一样的,难怪找不到:
上图中的同级中有个info.plist文件,本来以为改动里面的Executable file的名字,就可以了,没想到还是不行!
(无奈,重新合并,合并后的文件与原来的同名称):
各自环境编译完成,修改各自的执行文件的名字为:真机的StaticLibObjec1
和模拟器的StaticLibObject2
,执行合并生成StaticLibObject
:
$ lipo -create StaticLibObjec1 StaticLibObject2 -output StaticLibObject
然后把StaticLibObject
文件丢回去.framework文件夹。
再次编译,即可成功输出:
StaticLibObjectDemo[1980:867317] static lib sdk test method
至此,整个创建和使用bundle类型创建的framework全部完成。
制作静态库的注意事项
从这里搬过来的
1 )注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。
2 )图片资源的处理:两种静态库,一般都是把图片文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把它改名为.bundle就可以了,右键,显示包内容可以向其中添加图片资源。
3 )category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。
4) 如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。