1、认识静态库和动态库
首先 库 是对程序代码、函数及资源文件的封装,是一种共享程序代码,实现代码资源复用的方式。分为 静态库 和 动态库 。
静态库和动态库最明显的区别在于载入链接时期的不同,是相对于编译期和运行期而言的。
静态库 在程序编译时被链接到目标代码块,模块化提高代码的复用性,多次使用将多次拷贝,容易造成冗余,使得包变大。
动态库 在程序编译时不会被链接,而是在程序运行时才被动态载入加到内存中,系统只需要加载一次,供多个程序共享使用,共享代码节省内存空间。由于运行时动态载入的特性,我们可随时对库进行更新,而不需要重新编译代码,实现 动态更新 。但是可能会导致运行时错误且不易于定位和修复。
iOS8之前苹果不允许第三方框架使用动态方式加载,iOS8之后新增APP Extension,主APP需要和Extension共享代码;紧接着Swift语言机制不支持静态库(因为Swift运行库没被包含在iOS系统中而是打包进APP中,静态库会导致最终的目标程序中包含重复的运行库),于是推出 framework ,framework 既可以打包静态库又可以打包动态库。本文着重介绍如何使用framework打包静态库。有关静态库和动态库的知识可以自行深入学习,这里只做简单介绍。
2、封装framework静态库
- 创建framework
- 配置 Build Setting
修改 Mach-O Type
为 Static Library
,将链接时生成的执行文件类型设置成静态库类型
设置 Dead Code Stripping
为 YES
死码(代码被定义却从未被调用)剥离,去掉不会执行到的冗余代码,为编译包瘦身
设置 Build Active Architecture Only
为 NO
包含支持多种架构,否则为仅支持当前活跃架构的模拟器或真机。 Valid Architectures
可控制支持的架构,如舍弃 armv7 ,则不支持 4s 及以往机型,为打包瘦身。
真机(armv7=3gs-4s,armv7s=5-5c, arm64=5s-)
模拟器(i386=3gs-5,x86_64=5s-)
设置 framework 支持的最低版本
- 将 xib 、图像资源包含到 framework 中,将需要暴露的 .h 文件放在
Public
中,需要编译的 .m 文件放在Compile Sources
,并在建立 framework 时自动生成的头文件中加入要暴露的头文件.h
,否则会报 Warning
- 开始编译
选中真机/模拟器,Command+B 编译,分别生成只支持真机/模拟器的静态库,对.framework 右键 Show In Finder 可找到对应的静态库
3、制作通用静态库
有两种方法可合并上述生成的只支持真机、模拟器版本的静态库为通用库
- 使用终端输入命令行语句
lipo -create (此处填写真机 FrameworkDemo 文件路径) (此处填写模拟器 FrameworkDemo 文件路径) -output 自定义合成文件存储路径(合成文件的名字 FrameworkDemo ),生成合并后的 FrameworkDemo 文件,将此文件拷贝到相应的 FrameworkDemo.framework 中替换即可。
- 使用 Aggregate
- 创建 Aggregate
- 编写自定义 shell 脚本,选择当前 target,Command+B 编译
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# copy the header file to universal dir,make sure your "${CONFIGURATION}-iphoneos/usr" dir exists
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Create universal binary file using lipo
lipo -create "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
open "${UNIVERSAL_OUTPUTFOLDER}"
打开终端进入到对应目录查看静态库信息,使用 lipo -info
指令
我们便可直接使用 Debug-universal 里面合并后的通用版本 framework 了。以上打包的是 debug 模式
,若想发布可打包成 release 模式
,只需在 Edit Scheme
里设置即可。支持 `framework 静态库打包完毕。。
4、问题
-
当静态库中包含 Category 的时候,会报错,原因是跟 OC 的 runtime 机制有关。Objective-C 没有为每个函数、方法定义链接符号,它只为每个类创建链接符号。所以当我们在静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现”selector not recognized”,也就是找不到方法定义的错误。为了解决这个问题,引入了可以给链接器添加
-ObjC
标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来。 静态库中如果包含 xib 、图片等资源,使用 NSBundle 读取需注意资源路径,例如
self = [[[NSBundle mainBundle] loadNibNamed:@"xxxx.framewrok/TestView" owner:nil options:nil] lastObject] ;
img.image = [UIImage imageNamed:@"xxxx.framewrok/test.png"];
完结