.a /.framework /.bundle 理解与使用
前言: 为了防止世界被破坏,为了维护宇宙的和平,遂决定写下此文;
本文不对库文件(包括静态库,动态库).framework 及 .bundle 概念原理进行介绍,可自行查找资料;主要介绍如何创建静态库.a 资源集合.framework,资源包.bundle的创建使用;
.framework打包,并使用集合包agg集成的示例demo:示例demo
一:什么是静态库.a ,什么是资源集合.framework
(1.) .a 二进制库静态库文件;
(2.).a + .h + sourceFile = .framework。
.framework 资源集合;
二:使用背景
为什么使用.a ,.framework?
在某些情况下,我们或者其他开发者不想看到代码的实现,只需要调用我们的某个功能模块,这个时候,.a,.framework 就可以很好的解决类似的问题;
友情提示:你在创建静态库的时候一定遇到过一些错误,而在这些错误中常常会看到如下怪物:i386 ,x86_64,armv6,armv7,armv7s,arm64 (http://blog.csdn.net/lizhongfu2013/article/details/42387311);这些是什么,可以去查看iOS cup架构的资料,相信你一定会感激我的。注意区分真机和模拟器的区别。好的东西一定是从别人那里看,然后自己体会到的,别怪我不写明白,相信你一定会感激我的。
三:.a创建
打包静态库,如下图:
(1.)打开xcode ,快捷键command+shift + N 创建新工程:
选择static library 静态库,next
(2.)设置静态库名字为你需要的名字:
此时有.h .m俩文件:
(3.)将.m文件删除,拖入你写好的功能代码(.h ,.m ),或者,直接在当前.h .m中写入测试代码:
(4.)公开头文件
将你要公开的头文件,添加到targets->Build Phases->Copy Files->"+下,如图staticLibDemo.h默认已添加
(5.)最后在打包前要进行两项处理:
第一项:支持所有设备
模拟器 :(选中需要支持的模拟器设备)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO” ,编译
真机:(选中Generic IOS Deview)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO”,编译
编译之后会看到 静态库文件由红色变为黑色:
可以选中.a文件进入查看,包含include 和.a文件,如下图:
将支持不同arm处理器的.a合成一个通用.a(arm64 arm64e armv7 armv7s i386 x86_64这些指令集的处理器)
以命令 lipo -create 你刚生成的.a文件名称(vXXXX_64.a vXXXX_V7.a XXXX_V7s.a) -output XXXX_all.a 合成他们成为新的.a文件。
备注:如果需要真机模拟器64 32为都支持,可以分别选择当前版本最高模拟器和最高真机分别生成各自.a,然后将这两份.a合成一份。(我分别是在iphone 11 pro max 和 真机x max下生成的。然后测试了模拟器 6s,ipad mini 4,iphone 11 都没问题。真机测试了x max和iphone 6。我当前mac系统为:macOS mojave 10.14.6 ,xcode版本为11.1)
第二项:禁掉一些无用项,提高编译效率
在targets->Build settings下:
* Dead Code Stripping设置为NO
* Strip Debug Symbol During Copy 全部设置为NO
* Strip Style设置为Non-Global Symbols
注:当然第二项的设置不做也可以。
四:.a的使用
将刚刚创建好的.a文件和 StaticLibDemo.h 导入到你要加入这个静态库文件的项目中,然后在你的项目中调用即可,如图:
StaticTestDemo是我刚新建的项目,将你打包好的静态库文件.a和.h导入
然后在你的项目要使用静态库的地方,导入头文件,调用方法,如图:
可以看到,静态库中方法调用成功。
至此,.a创建,使用完成;
五:.framework创建
(1.)创建,如图
(2.)创建完成后的样子:
(3.)将功能模块拖入,如图
(4.)公开头文件:将project下要公开的头文件,拖入到public下;并在.framework的.h中导入公开的头文件,如图:
(5.)设置为静态库,如图:target->BuildSetting ->Linking->Mach O Type “Static Library”
(6.)
设置支持所有设备
模拟器 :(选中任意模拟器设备)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO” ,编译
真机:(选中Generic IOS Deview)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO”,编译
设置完成,编译运行,.framework由红变黑,成功;
(7.)使用:新建一个项目,将.framework导入到项目中,并在要使用的地方导入头文件,如图:
至此,.framework创建,使用完成;
六:.bundle创建,使用
(1.)创建:
在桌面创建一个空文件夹,在文件夹中放入要导入的资源文件,如图片等,
修改后缀为.bundle,如图:
选择添加
创建完成
(2.)将bundle包拖入项目中即可使用
七:多加入些知识吧:Aggregate
(1.)Aggregate是什么?是一个集合,就好比sdk。刚才你创建.a静态库文件和.framework的时候,有提到过,要创建模拟器和真机两种,而此处的Aggregate就是为了将两者都包含在一起,方便两种情况都可以使用的。(当然合并你制作的模拟器.framework和真机.framework的方法还有一种,使用命令的方法,此处不再赘述,可搜索.framework合并 。我习惯使用第一种方法。为什么?为了防止世界被破坏啊。)
(2.)好,马上来说下Aggregate如何创建:
(a.)在已经进行了模拟器和真机编译成功的.a 或者.framework中,Show in Finder 查看项目下文件内容,如图:(等下aggregate创建成功后对比)
(b.)创建aggregate,在targets下点击添加按钮“+”如图:
和之前找aggregate有区别,在Cross-platfrom下找到aggregate如图:
agg命名最好和你的库名一致如图:
现在,你的3个圈将创建完成了,接下来进行脚本配置:
(c.)新建一个脚本,如图:
- — - — - - — .a库的脚本如下 — - - — — -
— - - — - - — —将下边脚本复制到你刚新建的脚本中: — — - - — — - - - —
if [ "${ACTION}" = "build" ]
then
#要build的target名
target_Name=${PROJECT_NAME}
echo "target_Name=${target_Name}"
#build之后的文件夹路径
build_DIR=${SRCROOT}/build
echo "build_DIR=${build_DIR}"
#真机build生成的头文件的文件夹路径
DEVICE_DIR_INCLUDE=${build_DIR}/Release-iphoneos/include/${PROJECT_NAME}
echo "DEVICE_DIR_INCLUDE=${DEVICE_DIR_INCLUDE}"
#真机build生成的.a文件路径
DEVICE_DIR_A=${build_DIR}/Release-iphoneos/lib${PROJECT_NAME}.a
echo "DEVICE_DIR_A=${DEVICE_DIR_A}"
#模拟器build生成的.a文件路径
SIMULATOR_DIR_A=${build_DIR}/Release-iphonesimulator/lib${PROJECT_NAME}.a
echo "SIMULATOR_DIR_A=${SIMULATOR_DIR_A}"
#目标文件夹路径
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}
echo "INSTALL_DIR=${INSTALL_DIR}"
#目标头文件文件夹路径
INSTALL_DIR_Headers=${SRCROOT}/Products/${PROJECT_NAME}/Headers
echo "INSTALL_DIR_Headers=${INSTALL_DIR_Headers}"
#目标.a路径
INSTALL_DIR_A=${SRCROOT}/Products/${PROJECT_NAME}/lib${PROJECT_NAME}.a
echo "INSTALL_DIR_A=${INSTALL_DIR_A}"
#判断build文件夹是否存在,存在则删除
if [ -d "${build_DIR}" ]
then
rm -rf "${build_DIR}"
fi
#判断目标文件夹是否存在,存在则删除该文件夹
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
#创建目标文件夹
mkdir -p "${INSTALL_DIR}"
#build之前clean一下
xcodebuild -target ${target_Name} clean
#模拟器build
xcodebuild -target ${target_Name} -configuration Release -sdk iphonesimulator
#真机build
xcodebuild -target ${target_Name} -configuration Release -sdk iphoneos
#复制头文件到目标文件夹
cp -R "${DEVICE_DIR_INCLUDE}" "${INSTALL_DIR_Headers}"
#合成模拟器和真机.a包
lipo -create "${DEVICE_DIR_A}" "${SIMULATOR_DIR_A}" -output "${INSTALL_DIR_A}"
#打开目标文件夹
open "${INSTALL_DIR}"
fi
- - — - — —将上边脚本复制到你刚新建的脚本中 — — - — - — -
- - — - — - - — .framework的脚本如下 — - - — — - - — -
- - — - - — —将下边脚本复制到你刚新建的脚本中: — — - - — — -
# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"
- --------— —将上边脚本复制到你刚新建的脚本中 — — - — - —
如图:
运行如图:
最后,进入项目文件夹下,与第一步图对比:
发现此时得到我们需要的.framework。
最后,由于上边图片太多,在结尾温馨回顾下吧:
1. .a 静态库的创建使用:
(a.)打开xcode ,快捷键command+shift + N 创建新工程:选择static library 静态库,next
(b.) 设置静态库名字为你需要的名字:
(c.) 将.m文件删除,拖入你写好的功能代码(.h ,.m ),或者,直接在当前.h .m中写入测试代码:
(d.) 公开头文件: 将你要公开的头文件,添加到targets->Build Phases->Copy Files->"+下,如图staticLibDemo.h默认已添加
(e.) 最后在打包前要进行两项处理:
—-----— — - - 第一项:支持所有设备 - - - — — - — - — —
模拟器 :(选中任意模拟器设备)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO” ,编译
真机:(选中Generic IOS Deview)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO”,编译
编译之后会看到 静态库文件由红色变为黑色
可以选中.a文件进入查看,包含include 和.a文件;
- - — - — - - -第二项:禁掉一些无用项,提高编译效率 - — - --------—
在targets->Build settings下:
* Dead Code Stripping设置为NO
* Strip Debug Symbol During Copy 全部设置为NO
* Strip Style设置为Non-Global Symbols
注:当然第二项的设置不做也可以。
(f.) .a的使用
将刚刚创建好的.a文件和 StaticLibDemo.h 导入到你要加入这个静态库文件的项目中,然后在你的项目中掉用即可;
StaticTestDemo是我刚新建的项目,将你打包好的静态库文件.a和.h导入
然后在你的项目要使用静态库的地方,导入头文件,调用方法;
可以看到,静态库中方法调用成功。
至此,.a创建,使用完成;
2 .framework创建使用:
(a.)创建
(b.) 将功能模块拖入
(c.) 公开头文件:将project下要公开的头文件,拖入到public下;并在.framework的.h中导入公开的头文件;
(d.) 设置为静态库,如:target->BuildSetting ->Linking->Mach O Type “Static Library”
--— - —— — - -设置支持所有设备 - - - — — - — -
模拟器 :(选中任意模拟器设备)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO” ,编译
真机:(选中Generic IOS Deview)在targets->Build settings->Bulid Active Architecture Only-> 设置为 “NO”,编译
设置完成,编译运行,.framework由红变黑,成功;
(e.) 使用:新建一个项目,将.framework导入到项目中,并在要使用的地方导入头文件;
至此,.framework创建,使用完成;