iOS:Xcode7下创建 .a静态库 和 .framework静态库
Xcode7 中创建静态库:.a 和 .framework
一、简单介绍
1.什么是库?
库是程序代码的集合,是共享程序代码的一种方式
2.库的分类
根据源代码的公开情况,库可以分为2种类型
(1)开源库
公开源代码,能看到具体实现
比如SDWebImage、AFNetworking
(2)闭源库
不公开源代码,是经过编译后的二进制文件,看不到具体实现
主要分为:静态库、动态库
二、静态库和动态库
1.静态库和动态库的存在形式
静态库:.a 和 .framework
动态库:.dylib 和 .framework
2.静态库和动态库在使用上的区别
静态库:链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝(图1所示)
动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存(图2所示)
三、静态库简介:
1、静态库分为:
真机—Debug(调试)版本、
真机—Release(发布)版本、
模拟器—Debug版本、
模拟器—Release版本;
开发中一般都打包Release(发布)版本,将真机和模拟器版本合并,提供外界。
2、使用场景:在项目开发的过程中,例如两个公司之间业务交流,不可能把源代码都发送给另一个公司,这时候将私密内容打包成静态库,别人只能调用接口,而不能知道其中实现的细节。
四、用Xcode7创建.a静态库
.a文件版本(以制作SDWebImage静态库为例)
1、新建项目,点击iOS—Framework&—Cocoa Touch Static Library。
给你的工程命名为SDWebImageStaticLib
2、系统自动生成以工程名命名的.h和.m文件,可自定义的在目录下添加或删除文件,注意目录下Products文件夹有一个.a文件为红色,说明文件并不存在,需要接下来的处理就是将是自己写的库文件中所有的.m文件都放入.a文件中私有隐藏起来。
这里我们将系统生成的.h和.m文件删除。
3.选中TARGETS下的库文件名,创建对外暴露的头文件
创建完之后
4.将SDWebImage下的所有文件导入到SDWebImageStaticLib下
注意:第三步骤和第四步骤是可以调换的,只不过调换后需要手动的将需要暴露的头文件添加进去,所以不调换可以帮助我们完成。
此时默认的情况下,暴露的头文件都在Project下,应该移动到Public下
之前:
移动后:
5、然后点击左上角,选择Edit Scheme,Build Configuration下选择Release,先注意检查下面Release是否为NO:Yes表示只编译选中模拟器设备对应的架构,No则为编译所有模拟器设备支持的cup架构(Debug版本同理),选择NO,然后分别在模拟器和真机下Command+B编译一下,会看到Products文件夹下的.a文件变为黑色,这个.a文件就是我们想要得到的静态库,这里会出现一个问题你先编译的模拟器会发现.a依然是红色,你需要模拟器和真机都编译后.a才会变成黑色,这应该是Xcode本身的问题。
<1>
<2>
<3>
这3步设置完后,选择真机模式编译一下,Command + B,此时看到.a静态库文件变成了黑色。
然后将上面的第<3>步改为Debug,再选择模拟器编译一下,Command + B,就创建了模拟器环境下的.a文件,截图如下一样。
可以在终端看到,真机Release发布模式和模拟器Debug测试模式的.a文件都存在
文件为:
6、合并真机和模拟器.a文件,在终端输入以下命令行:lipo -create 模拟器.a文件的路径 真机.a文件的路径 -output 合并后的保存路径(最终会得到一个合并后的libSDWebImageStaticLib.a文件,再将暴露出来的.h头文件一起复制出来。
7、使用:只需将libSDWebImageStaticLib.a和暴露出来的.h头文件导入工程目录下就可供外界使用,这样就很好的保护了自己的实现源代码,不被他人篡改和偷窃。
8.这里再补充一下:
<1>.文件大小.a文件的体积(一般情况下)
真机用的.a > 模拟器用的.a
所合成.a == 真机用的.a + 模拟器用的.a
<2>.
注:关于静态库对CPU架构的支持,首先了解iOS设备CPU架构方面的知识,ARM是微处理器行业的一家知名企业,arm处理器以体积小和高性能的优势在嵌入式设备中广泛使用,几乎所有手机都是使用它的。
模拟器:iphone4s~5 : i386 iphone5s~6plus : x86_64
真机:iphone3gs~4s : armv7 iphone5~5c : armv7s (静态库只要支持了armv7,就可以跑在armv7s的架构上) iphone5s~6plus : arm64
armv6, armv7, armv7s是ARM CPU的不同指令集,原则是向下兼容的。例如iPhone4S CPU支持armv7, 但它同时兼容armv6,只是使用armv6指令可能无法充分发挥它的特性。
查看静态库.a对处理器架构的支持,先cd到.a文件的路径下,命令行输入:lipo -info xxxxx.a
<3>.
如果库中还包含了一些资源文件(如图片等),那么资源文件也应该放在上面的文件夹中。
五、用Xcode7创建.framework静态库,以MJRefresh为例
1.新建工程并选择默认Target为Cocoa Touch Framework, 如图:
2.给你的工程命名为MJRefresh,生成的静态库将以标准的名称格式出现.即MJRefresh.framework
3、项目自动创建设置开放的头文件和存放资源的Bundle文件,可以看到一个红色的MJRefresh.framework空的静态库
4、删除自动生成的MJRefresh.h文件
5、导入MJRefresh框架中的所有文件,应该暴露出来的.h文件默认都在Project下
6、.framework中有些类可能是一些私有的辅助工具,不需要使用者看到,在这里只需要把开放出去的类放到Public下, 如图
7、然后选择模拟器和Debug模式,编译一下,Command + B,此时,虽然看到MJRefresh.framework仍为红色,其实已经生成能在模拟器上运行的.framework静态库,进入MJRefresh.framework目录文件下,以及使用终端可以看到生成的静态库。
选中静态库文件,获取绝对路径如下:
在目录下和终端可以看到生成的静态库
8、再选择真机,设置Release模式,编译一下,Command + B,此时,虽然看到MJRefresh.framework变成黑色,生成能在真机上运行的静态库文件。
在目录下和终端可以看到生成的静态库
9、我们随意选择一个静态库,点进去看这个库文件中的具体内容,可以看到一个MJRefresh可执行二进制的文件,资源MJRefresh.bundle,暴露出去的头文件Headers等
10、下面一步就是合并了,生成模拟器和真机环境下通用的二进制可执行文件MJRefresh,生成后看一下这个可执行文件使用的微处理器架构有哪些:
11.好了,合并替换完成,剩下的就是如何使用这个最终的MJRefresh.framework静态库了。
(1)我们可以随意选择一个生成的MJRefresh.framework,拷贝一下到桌面
(2)然后再将合并后生成的可执二进制文件MJRefresh拷贝一下,粘贴到桌面上这个MJRefresh.framework文件中,替换里面的MJRefresh,生成一个完成的静态库。
(3)打开MJRefresh.framework/Modules/module.modulemap文件,可以看到暴露的MJRefrsh.h文件被放在umbrella雨伞下保护起来了,所以我们需要将其他的所有暴露的.h文件放到MJRefresh.h文件中保护起来,不然会出现警告
(4)我们以为此时大功告成,可以测试代码了,结果出现如下错误:
为什么会这样的?因为我们做的是静态库,在使用的时候需要额外加一个步骤,要把Framework同时添加到‘Embedded Binaries’中
此时再测试,发现没问题了,大功告成,可喜可贺!
六、制作静态库的注意点
(1)注意:
无论是 .a 静态库还是 .framework 静态库,最终需要的都是:二进制文件 + .h + 其它资源文件
(2).a 和 .framework 的使用区别
.a 本身是一个二进制文件,需要配上 .h 和 其它资源文件 才能使用
.framework 本身已经包含了 .h 和 其它资源文件,可以直接使用
(3)图片资源的处理
如果静态库中用到了图片资源,一般都放到一个bundle文件中,bundle名字一般跟 .a 或 .framework 名字一致
bundle的创建:新建一个文件夹,修改扩展名为 .bundle 即可,右击bundle文件,显示包内容,就可以往bundle文件中放东西
建议:自己制作的静态库中要用到的图片资源,不建议直接以png的后缀名方式拖到项目中使用,而是推荐使用放到bundle文件中。这样可以避免静态库的图片名和使用静态库的项目中存在的图片产生冲突。
1)新建一个文件夹,把需要打包的资源图片放在里面
例如:
2)修改扩展名为 .bundle,敲回车,点击添加。
例如:
(4)多文件处理
如果静态库需要暴露出来的 .h 比较多,可以考虑创建一个主头文件(一般 主头文件 和 静态库 同名)
在主头文件中包含所有其他需要暴露出来的 .h 文件
使用静态库时,只需要#import 主头文件
实际上苹果官方就是这么做的,例如:#import <UIKit/UIKit.h>
(5).framework为什么既是静态库又是动态库
系统的 .framework 是动态库
我们自己建立的 .framework 是静态库
(6)静态库中包含了Category(分类)
如果静态库中包含了Category,有时候在使用静态库的工程中会报“方法找不到”的错误(unrecognized selector sent to instance)
解决方案:在使用静态库的工程中配置Other Linker Flags为-ObjC