Xcode创建.framework静态库

最近项目中的登录和支付模块,需要封装成静态库,做下记录及踩的坑。

库介绍

库是共享程序代码的方式

库从本质上来说是一种可执行代码的二进制格式,可以被载入到内存中执行。库分静态库和动态库两种;iOS中静态库有.a和.framework两种形式;动态库有.dylib和.framework形式,后来.dylib动态库又被苹果替换成.tbd形式。

静态库与动态库的区别:

静态库和动态库是相对于编译期和运行期的,静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为程序运行期间还需要动态库的存在。

同一个静态库在不同程序中使用时,每个程序都要导入一次,打包时也被打包进去,和程序形成一个总的工程文件。而动态库在不同程序中,打包时并没有被打包进去,只是在程序运行使用时,才链接载入(如系统的框架UIKit/Foundation等),所以程序体积会小很多,但是苹果不让使用自己的动态库,否则审核就无法通过(最近看到说项目中可以使用,条件是最低支持iOS8.0以上)。

创建framework静态库

1、新建项目,选择Cocoa Touch Framework;如果是创建.a静态库,则选择Cocoa Touch Static Library

Xcode创建.framework静态库_第1张图片
新建项目

区别:.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。 .a + .h + sourceFile = .framework。.framework其实是对.a文件的封装,建议用.framework.

2、导入需要打包的源文件

Xcode创建.framework静态库_第2张图片
导入需要打包的源文件.png

3、修改项目配置

(1)注意info.plist文件中的类型

Xcode创建.framework静态库_第3张图片
info.plist文件

(2)设置需要暴露的头文件,将需要暴露的头文件从Project处拖入Public处

Public是你期望公开的,Private下的头文件依然是可以暴露出来的,因此名字可能有些误导。在Project下的头文件才是“私有”的,因此,头文件应该放在Public下,或者在Project下。

Xcode创建.framework静态库_第4张图片
header文件设置

也可以使用的方法是:选中.h文件,改变Target Membership面板下的设置。

Xcode创建.framework静态库_第5张图片
header文件设置方法二

这里需要注意的是暴露出来的头文件中import的其他类也得添加到public中暴露出来。如果不想将import的类暴露出来,那么在头文件中用@class 然后在对应的.m文件中再import。

建议将暴露的.h文件导入到系统推荐的.h文件中,即建项目时自动生成的文件,此工程中的text.h文件,应该使用#import<>格式导入。

(3)设置编译模式,在Xcode菜单【Product】--->【Scheme】--->【Edit Scheme...】中

Xcode创建.framework静态库_第6张图片
设置编译模式

注意:debug:调试版本,系统本身也会有一些调试代码,此版本体积会稍大,运行会稍慢;release:发布版本,系统会去除调试代码,体积变小,运行速度变快,对用户来说没有明显感觉

如果此处不将Build Configuration改为Release,则打包出来的静态库会存于【Debug-iphoneos】和【Debug-iphonesimulator】两个文件夹下。

我们一般都使用Release模式,因为程序最终发布之后是Release版的,所以静态库也是在Release模式下使用。

(4)设置编译出的静态库包含的指令集

Xcode创建.framework静态库_第7张图片
设置指令集

模拟器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64

真机:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64

 armv7s这个架构, 在2014年10月份的xcode版本更新中, 取消了默认导出此架构. 可以不用支持此架构. 如果要支持, 需要手动添加3个架构.

如果这里,设置为YES,那么编译出来的.a静态库就只包含当前设备的指令集。 举个例子:如果我们选择iPhone 5模拟器【Command+B】编译,则编译出来的.a静态库只能用iPhone4s5模拟器跑程序,用iPhone5s6plus,则会报找不到x86_64的libFMDB库。 设置为NO,则会把所有指令集的都打包合并。

(5)修改生成的Mach-O格式

Xcode创建.framework静态库_第8张图片
设置格式

.framework可以是静态库也可以是动态库,系统的.framework都是动态库,而用户制作的基本上都是静态库,苹果不允许用户在程序中使用自己制作的动态库上线。

(6)其他设置:不设置也不会有太大的影响

特别是那些在二进制库中遗留下的设置,编译器提供给你一个选项,来消除无效代码:永远不会被执行的代码。当然你也可以移除掉一些debug用符号,例如某些函数名称或者其他跟debug相关的细节。

因为你正在创建framework供他人使用,最好禁掉这些功能(无效代码和debug用符号),让用户自己选择对自己的项目有利的部分使用。和之前一样,使用搜索框,改变下述设置:

Dead Code Stripping设置为NO

Link With Standard Libraries 设置为NO

Strip Debug Symbol During Copy 全部设置为NO

Strip Style设置为Non-Global Symbols

4、编译生成静态库

编译时,需要真机(选择Generic ios Device)和模拟器各编译一次,这样Products目录下的text.framework静态库才会变为黑色,右键show in Finder 可以进入Products目录

5、合并模拟器framework的二进制文件和真机framework的二进制文件

Xcode创建.framework静态库_第9张图片
需要合并的二进制文件

如果想要通用需要将模拟器使用的静态库与真机使用的静态库合并成一个静态库,可以使用终端命令来实现。

命令格式:lipo -create 模拟器framework的二进制文件路径 真机framework的二进制文件路径 -output 最终二进制文件路径

Xcode创建.framework静态库_第10张图片
命令行合并

每次合成文件时都会出现错误信息,控制台总会报错,但仍会生成.lipo文件的二进制文件,在网上看到的一种解决办法就是:将此文件名修改成需要合并的二进制文件的名称。

在用它替换掉之前的二进制文件,此时的.framework便是我们需要的静态库文件

合并后的二进制文件

注意:(1)如果创建的framework中使用了category类,则在使用framework的项目配置中【Other Linker Flags】需要添加参数【-ObjC]或者【-all_load】。

(2)打包的framework使用到一些图片、音频等资源时,需要我们创建一个bundle,命名为ABC.bundle,然后将资源放入bundle中。打包的时候,framework并不包含ABC.bundle。最后在要使用.framework的工程中,新建一个文件夹or group,然后把.framework和ABC.bundle一起拖进去,就可以啦。  

使用:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"XXXX" ofType:@"bundle"];

NSString *mp3Path = [[NSBundle bundleWithPath:bundlePath] pathForResource:@"Message_system" ofType:@"mp3"];

补充:打包成的静态库肯定是比源码类要大很多的,因为是由不同指令集不同设备的版本合并成的。所以如果你很在意你的app大小,并且也不是很需要打包成静态库的话,还是用原始类吧。 framework静态库中是可以包含图片资源的;而.a静态库中不能包含图片资源,只能另外创建一个目录存放。

参考:https://www.jianshu.com/p/43d55ae49f59

你可能感兴趣的:(Xcode创建.framework静态库)