iOS 最全动态库/静态库制作 Framework/.a

一、静态库

1.创建静态库工程

Xcode -> Create a new Xcode project -> iOS -> Static Library
image.png

2.将代码导入工程 选择Create groups(逻辑路径)
image.png

3.配置一些设置

(1)Build Active Architecture Only

Build Active Architecture Only 设置为NO的意思是当前打包的.a支持所有的设备.否则打包时只能用当前版本的模拟器或真机运行.
image.png

(2)Dead Code Stripping

Build Settings中Link下面的Dead Code Stripping设置为NO:先不进行死代码剥离。
image.png

(3)设置.a最低支持的版本
image.png

3.暴露头文件(.h)以供SDK使用者调用

(1)Bulid Phases -> Copy Files -> + 将所有.h Copy进工程
image.png

(2.1)创建Headers

Bulid Phases -> + -> New Headers Phase
image.png

(2.2)Headers -> + 导入所有头文件
image.png

(2.3)将所有需要暴露的头文件拖到public
image.png

4.在模拟器和真机中run四种模式

① debug 模式 模拟器运行
② debug 模式 真机运行
③ release 模式 模拟器运行
④ release 模式 真机运行
(1)X86_64 和 arm64 切换
使用模拟器运行,制作的SDK是X86_64
使用真机运行,制作的SDK是arm64
(2)编译配置
苹果架构分为x86_64(模拟器) arm64
苹果包分为 Debug 和 Release

一般都是使用arm64
调试时,使用Debug包,上线使用Release

(1)Debug 和 Release 切换

Release: 选中工程->Edit Scheme->Run->Build Configuration->Release

Debug: 选中工程->Edit Scheme->Run->Build Configuration->Debug
image.png

image.png

(2)Run工程获取SDK

Clean: Product -> Clean Build Folder
Run工程后,在Product->Show Bulid Folder in Finder -> Products 中获取SDK

通过Product找到位置:


image.png

静态库是以.a后缀结尾,动态库是以.framework 后缀结尾

使用真机运行可能出现的问题:
image.png

这是由于真机的系统版本低于工程设置的最低版本

修改工程的最低版本
image.png

5.模拟器和真机通用架构模式合并

(1)查看debug真机和模拟器架构

lipo -info 路径
a.查看debug真机
image.png
b.查看debug模拟器
image.png

(2)移除模拟器包含arm64架构

在合并模拟器和真机架构时,如果.a中都包含arm64架会导致真机和模拟器无法合并。报错:have the same architectures (arm64) and can't be in the same fat output file。

XCode12之前:
编译模拟器静态库支持i386 x86_64两架构
编译真机静态库支持armv7 arm64两架构
使用lipo -create -output命令可以将两个库合并成一个支持模拟器和真机i386 x86_64 armv7 arm64四种架构的胖子库。

然而XCode12编译的模拟器静态库也支持了arm64,导致出现真机库和模拟器库不能合并的问题。

解决方案1:

如果有静态库工程:Build Settings -> Excluded Architectures里按照这样设置一下,再编译合并就不会报错了。
image.png
解决方案2:如果手里只有.a或.framework文件

使用lipo remove命令将模拟器库的arm64架构移除

lipo 模拟器路径.a -remove arm64 -output 模拟器路径.a
deDerivedoate.png

(3)合并模拟器和真机架构

a.终端方式
 sudo lipo -create [模拟器路径] [真机路径] -output [合成路径/文件名(自定义)]

合并成功如下:
image.png

查看.a支持设备架构 模拟器+真机
image.png
b.脚本方式

(1)通过target创建 Aggregate
TARGETS.png
Multiplstform.png

(2)新建New Run Script Phase


Resource Tags Build Settings Build Phases Build Rules.png

(3).a合并脚本
# Type a script or drag a script file from your workspace to insert its path.
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.a

DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.a

SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.a

# 如果真机包或模拟包不存在,则退出合并
if [ ! -d "${DEVICE_DIR}" ] || [ ! -d "${SIMULATOR_DIR}" ]
then
exit 0
fi

# 如果合并包已经存在,则替换
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

mkdir -p "${INSTALL_DIR}"

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"

# 使用lipo命令将其合并成一个通用.a  
# 最后将生成的通用.a放置在工程根目录下新建的Products目录下  
lipo -create "${DEVICE_DIR" "${SIMULATOR_DIR}" -output "${INSTALL_DIR}"

#合并完成后打开目录
open "${SRCROOT}/Products"

fi

如下图:
Type soript or drop a soript f1le ro Ur workspase to 1nsert t5 path.png

写好脚本后执行run,会自动在在Product->Show Bulid Folder in Finder -> Products 生成静态库。

6.使用静态库

(1)文件(.h、.m)中封装好方法以及合并好生成的.a静态库

image.png
image.png
image.png

(2)将.h文件和.a库拖到需要集成的项目中

\color{red}{注意:1.如果要给别人调用静态库中的方法,那就必须将方法暴露到.h文件中,并复制一份.h文件供项目调用。}
\color{red}{2.自己制作的静态库中包含了另外的静态库,那需要将新制作的静态库和另外包含的静态库一并复制到项目中使用}

image.png

(3)将.h文件和.a库加到Build Phases中

a.将frameWorkTest1加到Compile Sourceas中
image.png
B.生成的.a静态库加在Link Binary With Libaries
image.png

(4)调用静态库方法

image.png
image.png
image.png

可能遇到的问题

报错2 duplicate symbols for architecture arm64

解决方案:
2 duplicate symbols for architecture arm64 常见问题,是在导入第三方SDK的时候出现的。
究其原因一定是SDK中包含了工程中原本存在的某个类:全文搜索找到此类,无用的话将其删除,有用改变名字即可。

二、动态库

1.创建动态库工程

Xcode -> Create a new Xcode project -> iOS -> Framework
Pasted Graphic 7.png

2.将代码导入工程 选择Create groups(逻辑路径)
ehoose eplions for adding these fikes.png

(1)本例创建动态库的名字为dynamicFrameWork,项目会自动生成一个名为dynamicFrameWork的头文件
dynamicFrameWork.png
w Created by Se sn 2921129.png

(2)在framework自动生成的dynamicFrameWork.h文件中导入你想用的头文件,如下图:
wimport &FoundationFoundation.png

(3)不在framework自动生成的dynamicFrameWork.h文件中声明头文件,在新工程使用时会报警告,如下图:

aimport “ViewController.h®.png

1.虽然编译没问题,但作为一个强迫症患者,还是在自动生成的.h文件中把需要用到的头文件全部导入。
2.使用时更加方便,只要#import <dynamicFrameWork/dynamicFrameWork.h>即可使用动态库中的包含的全部文件,更加节省代码。

大家可自定义自己的UI界面、功能或逻辑。代码写完后,可在路径TARGETS->Build Phases->Headers下将你需要暴露给外面调用的头文件添加到Public下面即可将文件拖入工程(步骤4中会说)

3.配置一些设置

(1)Build Active Architecture Only

Build Active Architecture Only 设置为NO的意思是当前打包的.a支持所有的设备.否则打包时只能用当前版本的模拟器或真机运行.
Basic.png

(2)Dead Code Stripping

Build Settings中Link下面的Dead Code Stripping设置为NO:先不进行死代码剥离。
Basic Customized.png

(3)Mach-O Type(库性质)

简单总结为
库性质决定库加载到运行时内存的时机、加载的库范围、库的共享权限
mach -O Type:一种文件格式,Mach Object文件格式,是Mac上的可执行文件类型 或者 目标文件(.o)。
以开发者制作三方库的场景为例解释:

Executable:  `静态库`,输出二进制
Dynamic Library:`动态非共享库`,输出动态链接库非共享库,程序`运行`时链接到`内存`,大部分场景下不可共享;app extension、部分macOS场景下可以共享
Bundle:`动态非共享库`,和Dynamic Library相近,不过需要手动调用函数加载
Static Library:  `静态库`,输出静态链接库,程序`编译`时拷贝到`内存`
Relocatable Object File:`静态库`,和Static Library类似,但体积更小

从结构上看:

1.Framework格式的库只是比Static Library格式的库多出一个文件夹,拥有一个独立的工作区
2.Framework格式的库中嵌入的依赖库可以和app环境的依赖库相同,并且不会产生duplicate symbol,因为Framework有独立的运行环境
3.Static Library格式的库中的依赖库和app环境依赖库相同时会有依赖冲突
4.Static Library格式的库的依赖的方法可以不实现,但Framework格式的库依赖的方法必须实现(objc)
5.Static Library格式的库不可包含图片等资源文件
6.Static Library格式的库的库在打包时会直接编译进app的二进制执行文件,Framework格式的库被打包进沙盒;如果观察过Product包内容时会发现使用<Static Library格式的库>或者<Framework格式的库且(mach -O Type = Static Library)>不会出现在Frameworks文件夹中,是因为编译进了app的二进制执行文件
7.开发者签名的Dynamic Library性质的库时在app extension中共享或者在macOS部分场景下共享;苹果官方的动态库有共享权限
8.制作三方库在考虑Static Library格式的库库或者Framework格式的库时:依赖图片资源,使用Framework格式的库;想要拥有完整的依赖关系,使用Framework格式的库,此时外界可能需要剔除Framework格式的库之外的依赖库,而采用Framework格式的库内的依赖库,否则虽然不会产生依赖冲突,但会增加包大小

Statlo Ubrary.png
1.选择Dynamic Library生成动态库,Static Library生成的是静态库。
2.由于iOS8之后才允许使用插入动态库,所以网上大部分教程在选MachO-Type的时候选择的是Static Library。但是.a静态库和静态framework无法访问库中的资源图片的。所以自己创建的framework如果想访问库中的资源文件,那么必须要是动态库。
3.自建动态库手动拖入的工程后,必须选择embed选项,否则的话,启动即崩溃。
4.静态库中关联的对象无法用KVO进行观察,不会触动KVO回调方法。
5.理解一下静态库和动态库点击地址进入

(4)设置.framework最低支持的版本

targ.png

不设置版本打出来的真机的framework只包含arm64架构,模拟器的framework只包含arm64和x86_64架构

(5)Link With Standard Libraries

Build Settings中Link下面的Link With Standard Libraries设置NO:避免重复链接
image.png

4.暴露头文件(.h)以供SDK使用者调用

TARGETS —> Build Phases -》 Headers

把要暴露给别人的文件,从Project 拖动到Public中既可
Sianing & Capabstes.png

5.在模拟器和真机中run四种模式

① debug 模式 模拟器运行
② debug 模式 真机运行
③ release 模式 模拟器运行
④ release 模式 真机运行
(1)X86_64 和 arm64 切换
使用模拟器运行,制作的SDK是X86_64
使用真机运行,制作的SDK是arm64
(2)编译配置
苹果架构分为x86_64(模拟器) arm64
苹果包分为 Debug 和 Release

一般都是使用arm64
调试时,使用Debug包,上线使用Release

(1)Debug 和 Release 切换

Release: 选中工程->Edit Scheme->Run->Build Configuration->Release

Debug: 选中工程->Edit Scheme->Run->Build Configuration->Debug
, dynamicFrameWork.png
Wan for the erecvtable to be launched.png

(2)Run工程获取SDK

Clean: Product -> Clean Build Folder
Run工程后,在Product->Show Bulid Folder in Finder -> Products 中获取SDK

通过Product找到位置:
dynamicFrameWork.framework.png

5.模拟器和真机通用架构模式合并

(1)查看debug真机和模拟器架构

lipo -info 路径
a.查看debug真机
Lost loain Wed Dec 174740 on tty$002.png
b.查看debug模拟器
ipo -info Users.png

(2)移除模拟器包含arm64架构

在合并模拟器和真机架构时,如果.a中都包含arm64架会导致真机和模拟器无法合并。报错:have the same architectures (arm64) and can't be in the same fat output file。
XCode12之前:编译模拟器静态库支持i386 x86_64两架构编译真机静态库支持armv7 arm64两架构使用lipo -create -output命令可以将两个库合并成一个支持模拟器和真机i386 x86_64 armv7 arm64四种架构的胖子库。
然而XCode12编译的模拟器静态库也支持了arm64,导致出现真机库和模拟器库不能合并的问题。

解决方案1:

如果有动态库工程:Build Settings -> Excluded Architectures里按照这样设置一下,再编译合并就不会报错了。
image.png
解决方案2:如果手里只有.framework文件

使用lipo remove命令将模拟器库的arm64架构移除

lipo 模拟器路径.framework -remove arm64 -output 模拟器路径.framework
MscBook-.png

(3)合并模拟器和真机架构

a.终端方式
 sudo lipo -create [模拟器路径] [真机路径] -output [合成路径/文件名(自定义)]

合并成功如下:
圖 dynamicFrameWorkTest.png
b.脚本方式

(1)通过target创建 Aggregate


image.png
image.png

(2)在Dependencies中添加dynamicFrameWork
Se source Tags Buld Serthos Buld Pases Buss Rudes.png
ROJECT.png

(3)新建New Run Script Phase
Resource Tags Build Settings Bulld Phasos.png

(4).framework合并脚本

# Type a script or drag a script file from your workspace to insert its path.
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework

DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework

SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework

# 如果真机包或模拟包不存在,则退出合并
if [ ! -d "${DEVICE_DIR}" ] || [ ! -d "${SIMULATOR_DIR}" ]
then
exit 0
fi

# 如果合并包已经存在,则替换
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

mkdir -p "${INSTALL_DIR}"

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"

# 使用lipo命令将其合并成一个通用framework  
# 最后将生成的通用framework放置在工程根目录下新建的Products目录下  
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"

#合并完成后打开目录
open "${SRCROOT}/Products"

fi

如下图:
T scriet or drag a ssript 5e ree Your workspace to.png

写好脚本后执行run,编译新 target,会自动在在Product->Show Bulid Folder in Finder -> Products 生成动态库。

6.使用动态库

(1)获取真机framework

在Product->Show Bulid Folder in Finder -> Products 中获取SDK,并拖入到新工程调用。
dynamicFrameWork.framework.png
a.如果你的framework合并了真机和模拟器会报错,如下:
Building for iOS, but the linked and embedded framework 'dynamicFrameWork.framework' was built for iOS + iOS Simulator.

解决方案:
将合并了模拟器和真机的framework剥离,只用真机的framework即可。如(1)图

b.注意事项

1.动态库的上架,只能上架真机版本,因为其结构不一样,是编译后的文件。因为苹果是不会让你上传模拟器版本到线上商店,这样会凭空增加app大小。
2.所以不需要合并真机和模拟器,选择真机架构framework拖入工程使用即可。如果动态库合并了真机和模拟器,编译会报错。(忽略步骤5.模拟器和真机通用架构模式合并)
3.静态库不同,静态库是会再通过编译,生成执行文件的。可以合并真机和模拟器。

提示:如果你非得用合并了的模拟器和真机的framework,你声明只能用#import "",不能使用#import <>。如下:(不建议这么弄,不需要的直接忽略这条)

#import "dynamicFrameWork.framework/Headers/dynamicTestView.h"
#import "dynamicFrameWork.framework/Headers/testFrameWork.h"
(2)配置framework的Embed属性
Genera Signing & Copablnes RSOUrCe Teps Into Buld Settings Build Phases Buld Rules.png
(3)调用动态库中的文件
(a).dynamicTestView工程(.m)
image.png
(b).testFrameWork工程(.h/.m)

.h文件:
image.png

.m文件:
image.png
(c).开始调用动态库
image.png

可能遇到的问题
image.png

Reason:image not found

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

推荐阅读更多精彩内容