iOS 制作 framework

什么是库

库是共享代码的一种方式。从本质上来说库是一种可执行代码的二进制格式,可以被载入内存中执行。在开发过程中,一些核心技术或者常用框架,出于安全性和稳定性的考虑,不想被外界知道,所以会把核心代码打包成库,只暴露出头文件以供他人使用。

库的分类

库分静态库和动态库两种。

  • 静态库

静态库有 .a.framework 两种形式。

.a 是一个纯二进制文件,要有 .h 文件以及资源文件配合, .framework 中除了有二进制文件之外还包含了资源文件,因此可以直接使用。总的来说,.framework 整合了 .a + .h + resources ,所以创建静态库最好还是用 .framework 的形式。

  • 动态库

存在 .framework.tbd 两种形式。

在 iOS8 之前,苹果不允许第三方框架使用动态方式加载,从 iOS8 开始允许开发者有条件地创建和使用动态框架,这种框架叫做 Cocoa Touch Framework。虽然同样是动态框架,但是和系统 framework 不同,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 时会被放到 app bundle 中,运行在沙盒里,而不是系统中。也就是说,不同的 app 就算使用了同样的 framework,但还是会有多份的框架被分别签名,打包和加载。

库的优劣

静态库:在链接时会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝
好处很明显,编译完成之后,库文件实际上就没有作用了。目标程序没有外部依赖,就可以直接运行。当然其缺点也很明显,就是会使用目标程序的体积增大

动态库:与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,库才会被动态加载进来。系统的动态库不需要拷贝到目标程序中,自建的动态库可以由工程内的多个库共享,因此可以减小程序的体积。但是,由于其把静态链接做的事情都搬到运行时来做,程序的启动会变慢

库的创建

下面演示动态库的创建过程。

你可以单独的为你的共享文件创建一个项目,也可以在已有的项目基础上添加静态库项目。我们这里采用后者。

  1. 创建 MyFramework

创建framework

创建好之后会为你添加一个 Framework 项目文件夹,并为你创建好了 MyFramwWork.h 文件,该文件用来存放你想要分享的文件。
MyFramework
2. 添加共享文件

选中你的 Framework 项目,添加你想要共享的文件,需要同时添加 .h.m 文件。

添加共享文件

  1. 导入共享的文件信息,可选
#import <Foundation/Foundation.h>

//! Project version number for MyFramework.
FOUNDATION_EXPORT double MyFrameworkVersionNumber;

//! Project version string for MyFramework.
FOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <MyFramework/PublicHeader.h>

#import <MyFramework/Tool.h> // 导入工具
  1. 配置 Framework 信息

配置支持的机型,默认即可。
支持的机型
配置库的类型为动态库。
动态库

  1. 配置 scheme,可选
    配置 scheme
    这一步决定了 Framework 是 Debug 还是 Release。

  2. 运行

选中真机或模拟器
选中 MyFramework 项目,运行环境决定了你所支持的环境。

  1. 获取 Framework

找到 Products 文件夹中的 MyFramewoek.framework 右键 Show in Finder 查看。

查看framework
可以看到,这里分别编译出了 Debug 下面的真机和模拟器包。

  1. 使用

选择某一种环境的 Framework,拉入测试项目,进行如下设置。

设置动态库
导入库的头文件信息,测试库中类的使用情况。

#import <MyFramework/MyFramework.h>
[[Tool new] print];

注:如果你的库依赖了系统库,则使用者也应当设置对应的依赖库。

静态库

静态库和动态库的创建的过程基本一直,只需要将 Mach-O Type 设置为 Static Library

库中的资源使用

关于库中资源使用的问题依旧是值得一提的。项目中的获取资源时,如果没有特地指定 bundle 默认都是在主项目 mainBundle,但是,如果你将文件放在 framework 中,那么资源读取就需要特别指定了。

下面通过图片资源获取来演示。

首先为你的资源创建自己的 bundle 文件夹并放入一张图片资源。
添加图片
那么图片资源的使用如下。

[UIImage imageNamed:[[[NSBundle mainBundle] pathForResource:@"Frameworks" ofType:@"bundle"] stringByAppendingString:@"/Images/author.png"]]
[UIImage imageNamed:@"Frameworks.bundle/Images/author.png"]

对于其他资源的获取,如 Xib,可能会涉及到 bundle 问题,这里推荐使用方法 -bundleForClass: 获取。

NSBundle* bundle = [NSBundle bundleForClass:Tool.class];

真机库和模拟器库的合并

通过模拟器编译的库无法在真机下使用,反过来也是一样。当你企图在真机情况下使用模拟器的库时,你会得到类似如下错误。

ld: symbol(s) not found for architecture arm64

这的 arm64 时真机的类型,在设置库所支持的类型时可以进行设置。

支持机型
模拟器的类型有:i386 和 x86_64。

那么,将两种库进行合并,以适应任何情况下的运行是非常有必要的。

查看库所支持的类型

通过终端进入到 framework 文件夹下,输入以下命令

lipo -info 库名称

$ lipo -info MyFramework
Architectures in the fat file: MyFramework are: i386 x86_64 

$ lipo -info MyFramework
Architectures in the fat file: MyFramework are: armv7 arm64 

这里合并介绍两种方式,一种是手动使用命令合并,另外一种用脚本自动完成合并。

  • 手动合并

在编译完两种 framework 后,我们通过下面的命令完成合并。

lipo -create 真机xxx.framework/xxx 模拟器xxx.framework/xxx -output 真机xxx.framework/xxx

上述命令表示将真机和模拟器下的xxx(指代你的项目)合并并输出替换真机framework下的xxx(也可以是模拟器下的)。

完成之后验证新的 framework。

$ lipo -info MyFramework
Architectures in the fat file: MyFramework are: i386 x86_64 armv7 arm64 

可以看到,新的 MyFramework 同时支持了真机和模拟器。

  • 脚本合并

手动合并的麻烦之处在于,手动完成两种类型的库的编译以及合并。那么就使用脚本解放你的双手吧。

创建 Aggregate

image.png

添加脚本

添加脚本
写入脚本
以下为脚本的信息,你仅需改变以下库名称即可,其中的注释已经非常明确。

# 配置两种目标文件路径和最终 framework 路径
FMK_NAME="MyFramework"
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# 临时的build文件夹
WRK_DIR=build
# 真机framework路径,注:这里是 release
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
# 模拟器framework路径注:这里是 release
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# xcode命令,编译项目
xcodebuild -target "${FMK_NAME}" clean
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator 
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos 
# 如果已存在,那么删除创建新的
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
# 复制真机framework文件到最终的路径,以便后面合并使用
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/" 
# 使用 Lipo 工具合并
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
# 删除临时文件夹,如果你想保留两种 framework,请注释下述命令
rm -r "${WRK_DIR}"
# 打开最终的 framework
open "${INSTALL_DIR}"

然后编译这个 Aggregate 项目即可。编译完成会自动打开库所在的文件夹。

总结

framework 分动态库和静态库两种,动态库动态连接,只有引用,因此运行速度慢于静态库,静态库编译时会拷贝一份,提前编译,速度快,但是因此拷贝的原因,包大小会增加。framework 同样分了模拟器库和真机库,我们通常需要将两者进行合并,方式可以通过手动也可以使用脚本自动,无论是何种方式,核心命令是一致的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值