iOS静态库制作

FAQ

静态库与动态库的区别

  • 静态库:在编译的时候被完整地链接到可执行文件中,同一个静态库在不同程序中使用,每个程序都得导入一次,打包时也会被包进去,使其成为程序的一部分。
  • 动态库:程序运行的时候由系统动态地加载进内存,供程序调用,本身并不是程序的一部分。(苹果在Xcode6中开放了iOS的动态库,在此之前是不允许使用的)

静态库/动态库形式

  • 静态库: .a 和 .framework
  • 动态库: .dylib 和 .framework (.dylib现已被苹果替换成.tdb)

两种静态库形式的区别

  • .a静态库:单纯的编译之后的二进制格式文件,必须配合.h即相关头文件以及必要的资源文件才能才工程中使用。
  • .framework静态库:除了二进制文件,还有头文件和资源文件(.framework = .a + .h + Source File),严格来说.framework是一个静态库包,包含静态库文件。

.a静态库的制作

【第一步】创建工程,工程命名即为最终输出的静态库名字。

【第二步】创建或导入要打包进静态库的文件,将需要用到的资源文件,统一放到bundle包中(关于bundle包,下面有会有介绍)。由于新创建的工程还没有编译,Products下的.a文件还未生成,显示是红色的。

【第三步】选择要导出的.h文件

【第四步】选择编译模式(Debug、release)
在release模式下编译出的静态库相比Debug模式生成的静态库会去掉源码中用于调试的部分,即用Debug宏限定执行的部分,因此体积会略小,而且会进行一些优化。因此通常调试时使用Debug模式下输出的静态库,发布时使用release模式下输出的静态库(本例将以Debug模式演示)。

Procduct-->Scheme-->Edit Scheme Build Configuration下设置编译模式,默认为Debug模式。

【第五步】设置静态库支持的平台架构

目前模拟器和真机总共有5种架构

架构平台机型(iPhone)描述
i386模拟器4S ~ 532位
x86_64模拟器5S ~ 现在的机型64位
armv7真机3GS ~ 4S32位
armv7s真机5 ~ 5C特殊的架构
amr64真机5S ~ 现在的机型64位

其中armv7s架构由于存在一定的问题,XCode6以后默认从标准架构列表中移除了,如果想要制作包含armv7s架构的静态库,可以在目标架构中添加armv7s。

但是由于armv7架构的静态库可以在armv7s设备上跑,因此通常不需要打armv7s的静态库,armv7和amr64就能够满足所有机型了。

要制作静态库,需要选择生成哪些架构的静态库。有两种选择:①生成当前平台对应架构的静态库 ②生成全平台架构的静态库。具体在 TARGETS-->Build Settings-->Build Active Architecture Only 中设置:

Debug项和release项分别针对Debug模式和release模式。值为YES表示只生成当前平台对应架构的静态库,值为NO表示生成全平台架构的静态库。例如,若在模拟器iPhone6s下编译,若当前模式下【Build Active Architecture Only】为 YES ,则生成的静态库只支持x86_64架构,若为 NO ,则生成的静态库包含模拟器所有平台的架构,即i386和x86_64。对于真机而言也是一样,若选择真机编译,【Build Active Architecture Only】同样决定了输出静态库所支持的架构。但是如果选择在【generic iOS Device】也就是【通用iOS设备】下编译,输出的静态库默认包含了全平台架构,也就是【Architectures】中指定的架构,默认为【standard architectures】,由于armv7s已经从标准架构列表中移除,因此最终输出包含armv7、amr64两种架构。

可以用下面命令来查看指定静态库所支持的架构。

lipo -info LIB.a

OK,为了输出支持全平台架构的静态库,确保将当前模式下【Build Active Architecture Only】设置为NO。

【第六步】输出静态库

当前目标是在Debug模式下输出模拟器和真机全平台架构的静态库。先输出真机架构的静态库,将目标运行设备选择为【Generic iOS Device】,然后【Command+B】,之后进入到Products目录(可以发现XCode工程中Products下的.a文件不再是红色的了,可以直接右键–show in finder进入到文件所在目录),会发现多了一个 Debug-iphoneos 文件,表明这是在Debug模式下编译的真机架构的静态库,里面是输出的.a文件和头文件,具体支持哪些架构可以通过lipo -info命令查看。

选择任意一种模拟器机型,同样【Command+B】编译,会在Products下输出一个Debug-iphonesimulator目录,里面就是模拟器架构的.a文件和头文件了。

【第七步】合并静态库
将真机架构的静态库和模拟器架构的静态库合并,使用命令

lipo -create 真机静态库.a 模拟器静态库.a -output 目标静态库.a

之前说了静态库要能使用需要配合.h文件以及资源文件(需要的话),但是资源包是不会自动输出的。手动输出后,最终得到这样一个完整的静态库文件

至此.a静态库已制作完毕,只要将整个文件add到工程里,然后引入头文件就能使用了,这里就不做演示了。

.framework静态库制作

【第一步】创建工程,工程名即为输出静态库名

【第二步】添加要打包的源码以及包装好资源文件的bundle包,默认生成的头文件若不用可以删掉

【第三步】选择要暴露的头文件

TARGETS-->Build Phases-->Headers 将project列表中要暴露的头文件移动到Public目录下。

【第四步】选择编译模式(Debug/release),同.a静态库制作,不再赘述
【第五步】设置输出静态库架构,同.a静态库制作,不再赘述
【第六步】设置Deployment Target

【第七步】将输出设置为静态库(默认为动态库)

TARGETS-->Build Settings-->Linking-->Mach-O Type 设置为 Static Library

【第八步】输出静态库。分别在真机和模拟器下编译工程,方法同.a静态库的制作过程。最终在Products目录下输出两个.framework文件,分别对应真机和模拟器架构,均为Debug模式下编译的。可以看到,头文件以及bundle包被一并输出到静态库中了。

【第九步】合并静态库,将真机架构的静态库与模拟器架构的静态库合并,需要注意的是合并的是两个.framework包内名为LIB的文件,这才是真正的静态库。

最后将合并出的静态库文件替换掉任意一个.framework包内的静态库文件,得到的.framework就是一个完整的静态库包。

使用时同样只要将.framework包add到工程中,源码中引入相应的头文件即可,至此.framework静态库制作完毕。

Tip

资源文件的处理

两种静态库,一般都是把资源文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把后缀改名为.bundle就可以了,右键,显示包内容可以向其中添加资源。

Bundle包内资源路径

静态库里如果用到bundle包里的资源文件,需要注意资源路径。因为整个bundle包会被原封不动地打到工程的main bundle里去,因此直接以资源名是获取不到资源的。以图片为例,一种方法是使用的时候写全资源路径:

    UIImage *image = [UIImage imageNamed:@"LIB.bundle/image"];

另一种方法是先获取到bundle的路径,然后获取资源:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"LIB" ofType:@"bundle"];
    NSBundle *LIBBundle = [NSBundle bundleWithPath:path];
    NSString *imagePath = [LIBBundle pathForResource:@"image" ofType:@"png"];
    UIImage *image = [[UIImage alloc]initWithContentsOfFile:imagePath];

另外对bundle中的图片,系统会自动适配,只要命名好该有的2x 3x就行了!不信的话在不同retina下把图片scale打出来看看!

含分类的静态库

分类(Category)是我们实际开发项目中经常用到的,把Category打成静态库是没有问题的,但是在使用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误“selector not recognized”,原因是Unix的标准静态库实现和OC的动态特性之间有一些冲突:OC没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现”selector not recognized”,也就是找不到方法定义的错误。解决这个问题的方法是在使用静态库的工程中配置other linker flags的值为-ObjC,它的作用就是将静态库中所有的和对象相关的文件都加载进来。

然而如果类库中只有category而没有类的时候这些category还是加载不进来,方法就是加入-all_load或者-force-load标记。-all_load会强制链接器把目标文件都加载进来,即使没有objc代码。-force_load在xcode3.2后可用,但是-force_load后面必须要指定具体的文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值