iOS架构之路01 -- 静态库.a文件的制作与使用

  • 库是共享代码的一种方式;
  • 从本质上来说库是一种可执行代码的二进制格式,可以被载入到内存中执行;
  • 库可分为静态库动态库,在iOS中静态库有.aframework两种形式,动态库有.dylibframework两种形式,后来.dylib被替换成.tbd形式;

静态库

  • 静态库在程序编译时会被拷贝到目标程序中,运行时不能再修改静态库,同一个静态库在不同程序中使用时,每个程序中都会拷贝导入一次,造成多份冗余拷贝,浪费内存空间;

动态库

  • 动态库在程序编译时只链接不拷贝到目标程序,运行时由系统动态加载到内存,供程序调用,系统只会加载一次,多个程序可以共用,节省内存;注意动态库不会被拷贝到目标程序中,所以程序体积会小很多,系统的框架UIKit,Foundation等都属于动态库,但苹果不让使用自定义的动态库,若使用则审核无法通过,

  • 系统的.framework是动态库,我们自己建立的.framework是静态库,所以说framework既可以是静态库,又可以是动态库;

.a与.framework之间的区别

  • .a是一个纯二进制文件,其不能直接使用,需要有.h文件配合才能使用;
  • .framework中除了二进制文件之外还有资源文件,其包括.a + .h + sourceFile = .framework, .framework是可以直接使用的;

为什么要使用静态库?

  • 方便共享代码,便于合理使用;
  • 实现iOS程序的模块化,可以将固定的业务模块化成静态库;
  • 向别人分享你的代码库,但是不想让别人看到你代码的实现,开发第三方SDK的需要;

iOS移动设备的CPU架构

  • 通常,我们知道电脑的CPU架构有X86和X64等,但是手机的主流CPU架构是ARM架构,因为采用ARM架构的CPU是一种微处理器,这种处理器功耗低,体积小,更适合手机使用,iPhone的CPU也是如此;
  • iOS设备常见的架构如下所示,分为模拟器与真机两大类:
Snip20210908_49.png

.a静态库的制作与使用

  • 本人使用的是Xcode12.4;

  • 第一步:打开Xcode,新建一个Static Library工程,如下所示:

    Snip20210906_4.png

  • 静态工程名称为MyCategory

  • 第二步:MyCategory工程创建成功后,默认会生成MyCategory.hMyCategory.m两个文件,删除MyCategory.m,保留MyCategory.h,然后在MyCategory.h文件中导入自己代码文件的所有头文件,如下所示:

    Snip20210906_6.png

  • 第三步:静态工程配置,为了能支持真机与模拟器,做以下的工程配置:

  • 针对Build Setting -> Architectures 即设置架构选项,我们来做以下详细的阐述:

    • Architectures:默认设置为arm64与armv7架构是针对真机的,说明苹果遗弃了armv7s的真机架构,如果加上armv7s需要我们手动添加
    • Build Active Architectures Only:表示编译文件是否仅仅只支持当前选中的设备所包含的架构;默认情况下Debug模式下为YES,Release模式下为NO;
    • Excluded Architectures:删除指定的架构;
  • 现做如下设置,注意我选择的Release模式,然后进行编译;

Snip20210908_51.png
  • 真机生成的.a文件支持 arm64armv7两种架构,如下所示:
Snip20210908_53.png
  • 然后切换到iOS模拟器,我选择的是iPhone8 Plus,再编译,生成的.a文件支持 arm64x86_64i386 三种架构,如下所示:
Snip20210908_54.png
  • 模拟器居然也支持arm64架构,觉得有点不可思议了,从网上查相关资料说是Xcode12才会支持,这就为真机与模拟器.a文件的合并,带来隐患,下面内容有提到;

  • 关于Architectures的其他选项保持不变,手动输入真机架构,如下所示:

    Snip20210908_57.png

  • 真机生成的.a文件支持arm64,armv7 与 armv7s三种架构,如下所示:

Snip20210908_58.png
  • 设置.a文件支持的最低系统版本 iOS Deployment Target iOS 9.0
Snip20210908_59.png
  • 第四步:手动导入自己代码的所有.h文件,如下所示:
Snip20210906_9.png
  • 第五步:编译前检查一下是debug模式还是release模式,我们需要选择release模式;
    分debug和release模式:
    Debug-iphoneos 文件夹里面的东西是用在真机上的
    Debug-iphonesimulator 文件夹里面的东西是用在模拟器上
    如果 Scheme 是 Release 模式,生成的文件夹就以 Release 开头;
    如下所示:
[图片上传中...(Snip20210906_13.png-7afaae-1630915674828-0)]
Snip20210906_13.png
  • 第六步:编译 Command + B,首先选择真机状态下进行编译,然后选择模拟器状态载进行编译,最后会生成libMyCategory.a静态文件,如下所示:
Snip20210906_14.png
  • 会看到Release-iphoneosRelease-iphonesimulator两个文件夹,分别为真机与模拟器的静态库文件;

  • 第七步:静态库文件合并,即将Release-iphoneosRelease-iphonesimulator两个文件夹下的.a文件合并称一个.a,以便同时支持真机和模拟器,合并后的.a大小大约是未合并.a文件的2倍左右;

  • cd 到 Products文件夹下,执行lipo -create Release-iphoneos/libMyCategory.a Release-iphonesimulator/libMyCategory.a -output CategoryLib.a,出现报错,如下所示:

Snip20210906_15.png
  • 其原因在于Xcode12 编译的模拟器库新增支持架构arm64,需将模拟器的arm64给排除出去即可,工程配置如下:
Snip20210906_16.png
  • 然后在真机与模拟器状态下,重新编译,最后cd 到 Products文件夹下,执行lipo -create Release-iphoneos/libMyCategory.a Release-iphonesimulator/libMyCategory.a -output CategoryLib.a,在Products文件夹下会生成一个CategoryLib.a静态库文件,如下所示:
Snip20210906_17.png
  • 执行file CategoryLib.a可查看其文件类型及支持的架构信息,如下所示:
Snip20210906_18.png
  • 第八步:.a静态库的导入使用,新建一个工程Test_AProject,然后导入上面制作的.a静态库文件CategoryLib.a
    • 在桌面上新建一个文件夹MyLib,然后将真机的include文件夹与合并后的.a文件复制到MyLib文件夹中;

    • MyLib文件夹拖入Test_AProject工程中,如下所示:

      Snip20210908_60.png

Snip20210908_62.png
  • 需要设置Test_AProject工程的配置,如下所示:

    Snip20210908_63.png

  • bulidPhase--> Link Binary with Libraries中必须导入.a文件

Snip20210908_64.png
  • 然后调用静态库CategoryLib.a中的函数方法,最后调用成功!!!
Snip20210908_65.png

参考文章:
https://blog.csdn.net/shifang07/category_9287774.html?spm=1001.2014.3001.5482

推荐阅读更多精彩内容