iOS|Framework静态库打包教程 揭秘大牛和萌新的操作究竟差在哪

本文主要讲述了如何从0打出一个名称为GaPersonFramework.Framework的静态库.
从而让大家了解Framework静态库是如何制作的.

其中,最关键的第5步,牛人和萌新有着各自不同的做法,想知道你是牛人水平,还是萌新水平么?
那么,请耐着性子看完本文吧O(∩_∩)O

1 明确要编译的指令集

首先,我们需要明确自己要打的库文件需要支持哪些指令集,指令集列表以及对应的设备如下:
armv7:
iPhone 3GS, iPhone 4, iPhone 4S, iPod 3G/4G/5G, iPad, iPad 2, iPad 3, iPad Mini
armv7s:
iPhone 5, iPhone 5c, iPad 4
arm64:
iPhone X,iPhone 8(Plus),iPhone 7(Plus),iPhone 6(Plus),iPhone 6s(Plus), iPhone 5s, iPad Air(2), Retina iPad Mini(2,3)
arm64e:
iPhone XS\XR\XS Max
i386:
32位设备的模拟器
x86_64:
64位设备的模拟器

一般情况下,我们只要编译得到armv7,arm64,i386,x86_64指令集的库就可以了.
arm64e可以使用arm64的库文件运行,armv7s 可以使用armv7的库文件运行.
虽然性能不能充分发挥,但是控制了库文件的大小.当然,如果要充分发挥设备性能,最好还是为arm64e和armv7s也构造库文件.

但是这里我们还是将目标定位arvmv7,arm64,i386,x86_64这四个体系.

2 创建Framework工程

下面,我们建立一个Framework工程,此类工程最终会输出一个Framework.
工程名字为GaPersonFramework.


系统默认为我们创建了一个GaPersonFramework.h文件


3 编写库文件

接下来,我们编写库文件.
在GaPersonFramework中会创建两个文件.
一个是GaPerson类,表示人类,该类有一个greet方法,简单地输出字符串"Nice to meet you,I am kind of GaPerson".
另一个是NSObject+GaPerson分类,分类中也定义了一个greet方法,输出字符串"Nice to meet you,I am kind of NSObject.".
代码比较简单,就不详细介绍了.


4 设置工程

4.1 设置库文件类型

选中Targets-GaPersonFramework->BuildSettings->Linking->Mach-O Type
设置为 Static Library.这个是静态库.
该选项默认是Dynamic Library,不是我们所需要的.


4.2 设置架构体系

在BuildSettings->Architectures选项栏中,有3个值需要选择:
**1,Architectures,设置为(ARCHS_STANDARD)** 在当前版本的Xcode中,(ARCHS_STANDARD)等价于arm64,armv7两个.
2,Build Active Architecture Only,在Release模式是设置为NO,Debug模式设置为YES.
是否只编译正在运行的设备对应的指令集的库文件.
Debug模式设置为YES,是为了加快调式速度.
Release模式设置为NO,是为了得到全部所需的指令集的库文件.
3,Valid Architectures,设置为arm64,armv7,i386和x86_64
当BuildActiveArchitectureOnlu为NO时,Xcode最终将编译得到ValidArchitecture和Architectures这两个选项的交集的指令集的程序.

4.3 添加公共头文件

1,在BuildPhases->Headers中,把要公开的头文件从Project区域转移到Public区域
在这里加入到Public区域的头文件,做成Framework库文件的时候才会暴露出来.

2,在GaPersonFramework.h中添加公开头文件

到此为止,需要的配置已经Ok,接下来构建库文件.

5 构建库文件

5.1 萌新之手动构建

1,编译arm64和armv7的版本

选择设备为Generic iOS Device,然后Scheme的模式选择为Release,然后cmd+B.


编译成功,在Products文件夹下就会有一个GaPersonFramework.framework出现.
注意这个库文件,只包含真机设备的指令集,并不是我们最终要的.


我们选中该文件,右键点击ShowInFinder
可以看到这个包在Release-iphoneos文件夹下,而子目录中的GaPersonFramework,就是我们的库文件.


使用以下命令查看一个库文件支持的指令集:
lipo -info LibPath

注意,只要把文件拖动到终端中,就会得到该文件的路径,千万不要一个一个字符敲.
可以看到,这个库文件包含armv7,arm64两个指令集的数据.

2,编译i386和x86_64的版本

接下来,随便选择一个模拟器,再次确认在Release模式下,cmd+B.


然后也会在Products中生成一个framework,我们ShowInFinder,发现这次这个库文件在Release-iphonesimulator文件夹下.


image.png

同样,我们查看这个库文件支持的指令集:


可以看到,这个库文件包含i386和x86_64两个指令集的数据.

3,合并两个版本

因为我们最终需要得到包含4个指令集数据的库文件,所以我们需要进行合并操作.

首先,我们随便复制一整套库文件,并命名为Release-all,并将该套文件下的GaPersonFramework删掉,因为我们要合并一个完整的.
其余的文件需要保留.


合并两个版本的库文件,需要使用以下命令:
lipo -create LibPath1 LibPath2 -output LibPath
其中的LibPath1和LibPath2是前面两个部分库文件的路径,后面的LibPath,是我们合并后得到的完整的库文件的路径.

完成之后,我们再次查看合并的库文件所包含的指令集:



现在就支持4个指令集了.

然后我们最终得到的库文件是GaPersonFramework.framework这个文件夹,里面包含了具备四个指令集代码的库文件,以及头文件.


手动构建就此结束.

5.2 大牛之自动构建

1,新建一个Aggregate工程
在原来的工程中,新建一个Cross-platform->Aggregate的Target.
名字可以随便起.
我起得名字为GaPersonFrameworkBuilder,因为这个Target的创建的目的就是为了自动构造GaPersonFramework.

2,创建构建脚本
GaPersonFrameworkBuilder->BuilderPhases->点击+号->New Run Script Phase

将以下脚本代码粘贴到代码区域.
代码的详细步骤,可以查看注释,已经很清楚了.

# 1 文件夹设置
# 1.1 设置要构造的Target的名称,如果和工程名称不一样,这里需要自己填写.
FMK_NAME=${PROJECT_NAME} 

# 1.2 构造后,存放库文件的文件夹.
INSTALL_DIR=${SRCROOT}/Products

# 1.3 构造后,存放Fat库文件的文件夹
# 该文件夹存放的是我们最终需要的合并了多个指令集的Fat库文件.
FAT_DIR=${SRCROOT}/Products/Fat
# Fat库文件的文件夹路径
FAT_LIB_DIR=${FAT_DIR}/${FMK_NAME}.framework
# Fat库文件的路径
FAT_LIB_PATH="${FAT_LIB_DIR}/${FMK_NAME}" 
echo "FAT_LIB_PATH is ${FAT_LIB_PATH}"


# 1.4 构造时,存放中间Thin库文件的文件夹.
THIN_DIR=${SRCROOT}/Products/Thin
# 真机的库文件夹路径
DEVICE_LIB_DIR=${THIN_DIR}/Release-iphoneos/${FMK_NAME}.framework
# 真机库文件路径
DEVICE_LIB_PATH=${DEVICE_LIB_DIR}/${FMK_NAME}
# 模拟器库文件夹路径
SIMULATOR_LIB_DIR=${THIN_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# 模拟器库文件路径
SIMULATOR_LIB_PATH=${SIMULATOR_LIB_DIR}/${FMK_NAME}

# 1.5 构造时的临时文件夹
# Xcode构造时存放库文件的临时文件夹路径
BUILD_DIR=${SRCROOT}/build 
# 存放真机库文件的临时文件夹
DEVICE_LIB_DIR_TEMP=${BUILD_DIR}/Release-iphoneos/${FMK_NAME}.framework
# 存放模拟器库文件的临时文件夹
SIMULATOR_LIB_DIR_TEMP=${BUILD_DIR}/Release-iphonesimulator/${FMK_NAME}.framework


# 2 构建
# 2.1 构建真机库文件
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build 
if [ -d "${DEVICE_LIB_DIR}" ] 
then 
echo "History dir exists,delete it"
rm -rf "${DEVICE_LIB_DIR}" 
fi 
echo "Create lib dir for device."
mkdir -p "${DEVICE_LIB_DIR}" 
cp -R "${DEVICE_LIB_DIR_TEMP}/" "${DEVICE_LIB_DIR}/" 
if [ -f "${DEVICE_LIB_PATH}" ]
then
echo "Framework for iphone os make success!"
else 
echo "Framework for iphone os make failed"
fi

# 2.2 构建模拟器库文件
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build 
if [ -d "${SIMULATOR_LIB_DIR}" ] 
then 
echo "History dir exists,delete it"
rm -rf "${SIMULATOR_LIB_DIR}" 
fi 
echo "Create lib dir for simulator."
mkdir -p "${SIMULATOR_LIB_DIR}" 
cp -R "${SIMULATOR_LIB_DIR_TEMP}/" "${SIMULATOR_LIB_DIR}/"
if [ -f "${SIMULATOR_LIB_PATH}" ]
then
echo "Framework for iphone simulator make success!"
else 
echo "Framework for iphone simulator make failed"
fi


# 3 合并
# 3.1 确保Fat库文件夹是空的
if [ -d "${FAT_LIB_DIR}" ] 
then 
echo "History file exists,delete it"
rm -rf "${FAT_LIB_DIR}" 
fi 
echo "Create lib dir for fat."
mkdir -p "${FAT_LIB_DIR}" 

# 3.2 拷贝一个已经存在的库文件的文件夹
echo "Copy device framewoke file"
cp -R "${DEVICE_LIB_DIR}/" "${FAT_LIB_DIR}/" 

# 3.3 将合并后的库文件放入Fat库文件夹内.
lipo -create "${DEVICE_LIB_PATH}" "${SIMULATOR_LIB_PATH}" -output "${FAT_LIB_PATH}"
# 4 清理
# 删除Xcode构建临时文件夹
rm -r "${BUILD_DIR}" 
# 删除Thin库文件夹
rm -r "${THIN_DIR}"
# Finder 打开Fat库文件夹
open "${FAT_DIR}" 

3,运行脚本
Scheme选择GaPersonFrameworkBuilder,设备选择Generic iOS Device,然后cmd+B,就会执行该脚本进行构建.

构建完毕后,Finder会打开Fat文件夹,我们所需要的framework框架直接就在眼前了.
其实该脚本做的事情,和第一种做法是一样的,只不过用脚本来实现了..


6 使用库文件

新建一个工程,名称为GaPersonProject.
在这个工程中,我们要导入前面做好的Framework库文件,并使用该库文件.

1,在工程中,将库文件拖入工程,然后引入头文件.
将前面Fat文件夹得到的GaPersonFramework.framework拖动到工程中.

在使用库文件的地方导入库的头文件.
#import <GaPersonFramework.framework/GaPersonFramework.h>

2,设置编译标志
但是此时调用分类的方法会报错.
因为在调用framework的时候,分类中定义的方法并不能直接被调用.
Objective-C不会为每一个objc函数生成链接符号,而是会为每一个类生成链接符号。所以对于分类,那么链接器就不知道如何把原代码与category的代码实现关联起来,导致生成的对象无法响应属于分类的消息。

解决办法:
Linking->Setting->Other Linker Flags,添加-ObjC选项。

加了这个参数后,链接器就会把静态库中所有的 Objective-C 类和分类都加载到最后的可执行文件中,但这些额外的代码会使目标文件变大。


image.png

Demo下载

本文中的两个工程可以在此下载:
链接: https://pan.baidu.com/s/1lnOYLq9OjSK4zwcidEff7g
密码: mbjt

文章推荐

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,737评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,103评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,710评论 0 326
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,909评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,794评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,557评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,939评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,572评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,852评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,871评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,692评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,490评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,939评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,114评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,409评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,971评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,176评论 2 339