Quantcast
Viewing all articles
Browse latest Browse all 5930

iOS静态库制作

QA

静态库与动态库的区别

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

静态库/动态库形式

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

两种静态库形式的区别

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

.a静态库的制作

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

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

Image may be NSFW.
Clik here to view.

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

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

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

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

Image may be NSFW.
Clik here to view.

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

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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命令查看。

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

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

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

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

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

.framework静态库制作

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

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

Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

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

Image may be NSFW.
Clik here to view.

使用时同样只要将.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后面必须要指定具体的文件。

作者:Lotheve 发表于2016/10/14 11:17:26 原文链接
阅读:31 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>