iOS打包静态库

一、前言

“隔着一段距离看,很多有趣的知识看起来都很唬人。”在我初出茅庐的时候着实觉得那些后缀名为“.frameworke”、“.a”、“.dylib”的文件很神秘,很高冷。那时我虽然知道只要导入一个库就能引用库里面很多封装好的东西,但对这个“库”究竟是什么“鬼”,一直都是云里雾里。后来开发中有打包的需求,然后就去找了些文章,但是都不是太全面,而且自己操作中有些小细节的地方也是挺坑的,就想写下自己打包过程中遇到的细节和坑,希望对你们有帮助。好了废话不多说,看下去就知道它是个什么“鬼”。

二 、一些概念的补充

1、 什么是库?

所谓库就是程序代码的集合,是共享程序代码的一种方式。

2、 库的分类

根据程序代码的开源情况,库可以分为两类

开源库

源代码是公开的,你可以看到具体实现。比如GitHub上比较出名的第三方框架AFNetworking、SDWebImage。

闭源库

不公开源代码,只公开调用的接口,看不到具体的实现,是一个编译后的二进制文件。这种常见于一些公司的SDK包,比如高德地图SDK、环信即时通讯SDK等等。而闭源库又分为两类:静态库和动态库。本篇重点要讲的便是其中的静态库。

3、静态库和动态库的存在形式和使用区别

存在形式:

静态库

以".a"或者“.framework”为文件后缀名

动态库

以".dylib"或者“.framework”为文件后缀名

使用区别:

静态库链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝。


静态库被程序使用时

动态库链接时不复制,程序运行时由系统动态加载到内存,供程序调用。而且系统只加载一次,多个程序共用,节省内存。


4、iOS 设备的CPU架构

模拟器:

4s-5: i386

5s-7 Plus: x86_64

真机(iOS设备):

armv6: iPhone、iPhone 2、iPhone 3G、iPod Touch(第一代)、iPod Touch(第二代)

armv7: iPhone 3Gs、iPhone 4、iPhone 4s、iPad、iPad 2

armv7s: iPhone 5、iPhone 5c (静态库只要支持了armv7,就可以在armv7s的架构上运行)

arm64: iPhone 5s、iPhone 6、iPhone 6 Plus、iPhone 6s、iPhone 6s Plus、iPad Air、iPad Air2、iPad mini2、iPad mini3

:真机iPhone7、iPhone7 Plus A10处理器到底是什么架构暂时不得而知,没查到相关资料,貌似还没公布,但是模拟器是x86_64。

5、a与.framework有什么区别?

.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。

.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。

.a + .h + sourceFile = .framework。

建议用.framework.

6、制作静态库时的几点注意:

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暴露出来就可以了。


三、进入主题:打包静态库!

.a文件静态库打包

1、打开Xcode创建一个新的工程,这里以Xcode8为例,选择工程如下:

创建一个新工程

2、创建工程完毕后,界面如下(以打包SDWebImage为例)


系统会默认帮我们生成两个文件,可以只留一个.h文件然后把SDWebImage框架的所有文件拖拽到工程里面,然后把想暴露的头文件写在SDWebImage.h里面(也可以俩个文件都删除,把框架的文件都拖拽进去)。

我们知道静态库存在的最大意义是隐藏代码的具体实现,但是这也隐藏的太彻底了,总要公开些接口或者头文件供人调用吧。

3、公开接口头文件

targets->Build Phases->Copy Files->"+"你需要公开的头文件

添加对外公开的头文件

选择需要对外公开的.h(建议添加所有的.h,如果你只想对外提供部分的.h,要保证这些.h里面没有导入其他未添加到Copy Files的.h,否则你在编译后生成的.a在使用的时候就会报错)输入.h,然后command+a 全选,点击Add

快捷添加

4、设置适配所有架构

project -> buildSeting -> Build Active Architecture Only 设为NO

设置适配所有架构

5、运行工程进行打包

command + b 编译就会生成静态库了,

查看静态库
静态库目录

Debug-iphoneos 这个就是Debug模式的真机静态库,

可以通过选择Run的info设置 Debug 和 Release,设置Debug和Release。

通过选择Generic iOS Device 和 模拟器,设置真机和模拟器。

所以你会得到四种静态库:

Debug-iphoneos      Debug-iphonesimulator

Release-iphoneos      Release-iphonesimulator

Debug和Release设置

6、终端查看静态库所支持的架构

终端->cd进入库文件路径(Debug-iphoneos这个目录下面)->lipo -info 库名(lipo -info libSDWebImage.a)                         文件的路径:可以通过直接拖拽文件到终端

或者      终端->lipo -info .a的路径

查看静态库支持的架构

可以看到支持 armv7 arm64(静态库只要支持了armv7,就可以在armv7s的架构上运行)

如果不设置第4步:project -> buildSeting -> Build Active Architecture Only 设为NO,生成的静态库只会支持当前选择的模拟器或者真机的架构。

7.合并真机和模拟器的静态库

进入电脑的终端命令,进入到product的目录文件下,执行命令cd+product的文件路径

lipo -create 静态库1路径 静态库2路径 -output 合并的静态库名字(libSDWebImage.a)

lipo -info 静态库路径  查看静态库支持的架构,可以看到能够支持所有的架构了。

看了好多文章有说Debug和Release也能合并,但是没搞出来,有成功的麻烦也告知下我。


.frameworke文件静态库打包

1、依然Xcode创建一个新的工程FrameworkeLib,选择工程如下:(以打包MJRefresh为例)


2、创建完成后我们可以看到,工程本身自带一个MJRefreshFramework.h文件,这是类似一个主头文件一样的东西。


然后把SDWebImage框架的所有文件拖拽到工程里面。


这里将MJRefresh.h删除了(不需要了),需要暴露的头文件写在MJRefreshFramework.h里面,以这样的形式#import


3、设置支持所有模拟器架构或真机架构(和打包.a第4步骤一样)

4、公开头文件

target-Build Phases - Headers -把需要公开的头文件从project拖入Public 或者右键Move to public Group(这里将全部头文件添加进去,根据需求添加想要暴露的.h,不要出现Public里的.h有import Project里的.h,被坑过)


5、设置打包的是静态库。因为动态库也可以是以framework形式存在,所以需要设置,否则默认打出来的是动态库

target->BuildSetting ->搜索关键字mach->Mach-o Type 设为Static Library(这个默认选项是动态的)


6、选中真机(可以选择手机或者Generic iOS Device)或模拟器运行设备打包(与打包.a一样command + b),完成后Products文件夹下的MJRefreshFramework.framework文件由红色变成了黑色,右键show in finder


合并和查看静态库支持的架构和上面一样   

四、使用静态库 

使用的时候把合并的静态库拖拽到工程即可(如果有资源文件如bundle,还需要手动添加进去,系统不默认添加)

还有最近刚出xcode9试了下,好像编译打包在Products下面是没有静态库的,只好用xcode8了,还有如果用xcode9打开的项目,你在拖拽打包好的静态库到工程里面后Targets->select you target-->Build Phases->Link Binary With Libraries里面不会自动添加静态库,需要手动添加(很扯淡)



END

推荐阅读更多精彩内容