静态库制作及注意点

使用库无外乎就是两种情况:一种是将源码的实现细节隐藏,只给外部调用的接口集成特定的服务,如常见的百度/谷歌地图等等第三方库;另一种就是防止公司的核心代码泄露,将核心功能的源码打成库文件集成。

关于库

库一般分为静态库和动态库两种,其本质上来说是可以被载入内存中执行的可执行代码的二进制格式。
iOS中的静态库有.a.framework两种形式;动态库有.dylib.framework形式,.dylib动态库从Xcode 8开始以.tbd的形式出现。

动态库和静态库的区别:

  • 静态库在链接时会被完整的复制到可执行文件中,被多次使用就有多份冗余拷贝。
  • 动态库链接时不复制,程序运行时由系统动态的加载到内存供程序调用,系统只加载一次,多个程序共用,节省内存。

.a静态库.framework静态库区别

  • .a静态库是纯二进制文件,不能单独使用,一般需要配合头文件使用。
  • .framework静态库可以单独使用,并且可以集成资源文件,类似于.a + .h + sourceFile = .framework

.a静态库

库文件生成

  1. 新建项目,如图选择新建静态库:
    静态库命名一般以lib开头,后面加上静态库的功能,如我这个静态库用于蓝牙加解密,所以命名为libBLECrypto
  2. 完成之后会自动生成项目名称同名的.h.m文件。
  3. 我们根据需求实现功能及导入相关的文件,此时如果我们不编译,默认Products目录下会有一个红色的lib+ 项目名称 + .a的文件。
  4. Command + B编译一下项目,此时该文件变为黑色。我们在该.a文件上右键Show in Finder,进入其所在位置,实质上项目中的.m文件已经生成.a文件了。但是此时别人是无法使用的,因为缺少对应的头文件,我们需要再如下位置配置需要暴露给外界的头文件信息:
  5. 配置完成后重新Command + B编译后会发现在原来生成的.a文件的同级目录会生成一个include目录,里面就是需要一起提供给调用者的头文件信息。
  6. 进行到这里是不是感觉.a静态库的制作很简单?不要闹,我们还有更重要的事情没有解决呢。

环境及平台处理

  1. 我们知道生成的静态库可能用于Debug模式,也可能用于Release模式;可能是在模拟器上面运行,也可能是在真机上运行,既然有这么多可变因素,那么我们就需要一一解决。

  2. 我们首先将不同的开发模式和不同的运行环境下生成对应的库文件(共4种):

    • 模拟器 + Debug
    • 模拟器 + release:
    • 真机 + Debug
    • 真机 + release

  3. 这里有一个注意点,需要将构建建构设置为NO,否则只支持选中的设备架构:

  4. 使用lipo -info命令查看静态库支持的CPU架构,如

  5. 可以看出使用真机编译生成的静态库是支持armv7 arm64架构的,使用模拟器编译生成的静态库是支持i386 x86_64架构的(armv7是兼容armv7s的)。

  6. 关于设备的CPU架构(指令集)

    • 模拟器:
      • i386 : 32位架构 4S ~ 5
      • x86_64 : 64位架构 5S ~ 现在的机型
    • 真机(iOS设备):
      • armv7 : 32位架构 3GS ~ 4S
      • armv7s: 特殊的架构 5 ~ 5C
      • amr64 : 64位架构 5S ~ now
  7. 根据使用者的需求,将对应的库文件及头文件提供给调用者即可,但是如果在模拟器和真机之间切换使用这样比较麻烦,所以需要将两个静态库合并为一个静态库供别人使用。

静态库合并

  1. 将静态库合并也比较简单,只需要需要支持的架构的静态库合并即可,一般我们主要合并模拟器Release下的静态库和真机Release下的静态库,保证在模拟器和真机下都可以调试并且可以发布应用。合成指令如下:

    1
    lipo -create 静态库1.a 静态库2.a -output 新静态库.a
  2. 合成完成会生成一个新的.a静态库,将该.a静态库和头文件一起提供给调用者即可。

静态库上架

  1. 如果项目中导入了.a静态库且上架需要开启Bitcode选项,那么静态库就需要支持Bitcode才可以,否则打包上架会遇到如下问题:

    1
    ld: bitcode bundle could not be generated because 'xxx.a(xxx.o)' was built without full bitcode.
  2. 让静态库支持,需要在编译生成静态库文件前进行下面两步配置

    • 需要在Build Settings中设置Enable Bitcode选项为Yes(默认是开启状态)。
    • Build SettingsOther C Flags添加-fembed-bitcode参数。
    • 检查生成的静态库文件是否支持Bitcode,请使用如下指令:
      1
      2
      3
      otool -arch armv7 -l libBLECrypto.a 
      或者
      otool -arch arm64 -l libBLECrypto.a
    • Command + F搜索bitcode字段,如果存在sectname为bitcode的字段且对应的size不是0x0000000000000001,说明静态库支持Bitcode

.framework静态库

可以采用cocoaPods的方式构建

注意点

如果静态库中使用到分类,那么直接使用静态库会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的添加-ObjC
如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。
如果我们在同一电脑行生成静态库并配置到其他项目中,此时在项目中打断点是可以进入静态库的实现文件中的,不过不用担心,在其他电脑是以汇编形式显示的。