iOS 中 framework 和 bundle 的制作

我的博客原文地址

Framework

Framework资源的集合,将静态库和其头文件包含到一个结构中,让 Xcode 可以方便地把它纳入到你的项目中。

在运行时,库中按你的想法暴露需要的头文件,整个工程都可以调用暴露出来的接口和参数,这样减少了内存消耗,提高了系统的性能。

为什么使用 framework

与别人分享自己开发的组件,有两种方式。

  • 直接提供源代码。
  • 将组件代码编译成静态库,供他人调用。

第一种方式容易被人看到具体实现的细节,这些可能是你不想暴露出来的。此外,开发者也可能并不想看到你的所有代码,而仅仅是希望将功能的一部分植入到自己的应用中。

因此很多组件的封装采用第二种方式,这也是下文介绍的主要内容。

配置静态库工程

步骤1:打开 Xcode ,依次点击 Create a new Xcode project → iOS → Cocoa Touch Framework,在 Product Name 中填写名称。(注:这就是最后 framework 的名称。)

步骤2:假如你的项目依赖某些系统库,那么需要通过点击 Targets → Build Phases → Link Binary with Libraries,点击 + 符号将它们添加到工程中。

步骤3:修改 Project 中的 iOS Deployment Target 版本号,选择你的框架最低支持的 iOS 版本。

步骤4:如果组件中存在 .xib 文件,请确保 TARGETS → Build Phases → Copy Bundle Resources 下存在该 xib 文件。

步骤5:将封装好的组件文件夹拖入到项目目录下,选择你要公开的头文件。

步骤6:依次点击 TARGETS → Build Phases → Headers,目录下有:

  • Public:存放公开的头文件,给外部调用。
  • Private:存放私有的 Header,但头文件在编译之后还会存在。一般用来存放项目中需要调用但又不想给别人看到其内部实现的文件。
  • Project:隐藏的文件。

导出 framework

选中 Scheme 选择当前项目,然后右边设备依次选中 Generic iOS Device(通用真机版本)和任一模拟器,分别编译(command + B),成功将会自动跳转到打出的 .framework 文件相应的目录下。

合成 framework

为了让用户能统一调用一个 framework ,还需要将二者合成为一个 framework 。这里介绍一种简单的方法:

1、新建一个 target,依次点击 TARGETS 左下角的加号按钮 → Cross-platform → Other 下的 Aggregate

2、点击工程文件,选 TARGETS → 刚才创建的 Aggregate → Build Phases → + → New Run Script Phases。在当前栏目里会多出一个 Run Script ,在里面输入以下脚本:

#!/bin/sh
#要build的target名
TARGET_NAME=${PROJECT_NAME}
if [[ $1 ]]
then
TARGET_NAME=$1
fi
UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}/"

#创建输出目录,并删除之前的 framework 文件
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"
rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework"

#分别编译模拟器和真机的 framework
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#拷贝 framework 到 univer 目录
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}"

#合并 framework,输出最终的 framework 到 build 目录
lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#删除编译之后生成的无关的配置文件
dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
#判断 build 文件夹是否存在,存在则删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi
rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"
#打开合并后的文件夹
open "${UNIVERSAL_OUTPUT_FOLDER}"

3、使用脚本进行编译 (command + B),成功后将会自动跳转到打出的 .framework 文件相应的目录下。

查看是否成功

步骤1:打开终端,进入到你的 framework 文件所在的目录

cd ${yourFrameworkName}.framework

步骤2:查看架构支持

lipo -info ${yourFrameworkName}.framework/${yourFrameworkName}

可以看到输出:

Architectures in the fat file: ${yourFrameworkName} are: i386 x86_64 armv7 arm64 (支持的架构显示在这)

设备的CPU架构(指令集)

  • 模拟器
    • i386: 针对 intel 通用微处理器32架构,如 iPhone 4s-5:
    • x86_64: 针对 x86 架构的64位处理器
  • 真机
    • armv6: iPhone、iPhone 2、iPhone 3G、iPod 1G/2G(Xcode4.5起已不再支持armv6)
    • 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 5s、iPhone 6(Plus)、iPhone 6s(Plus)、iPad Air(2)、Retina iPad Mini(2,3)
    • arm64e: iPhone XS\XR\XS Max

引入 framework 的注意事项

引入的 framework 里存在分类的话,编译运行项目会报形如 xxx unrecognized selector sent to class xxx 的错误。

解决办法:

选中左边栏的项目文件,然后依次点击 Targets → Build Settings → Linking → Other Linker Flags,在里面添加 -ObjC 再次编译就能正常运行。

补充知识:

从 C 代码到可执行文件经历编译步骤是:

源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件。

在最后一步需要把 .o 文件和 C 语言运行库链接起来,这时需要用到 ld 命令。源文件经过一系列处理后,会生成对应的 .obj 文件,一个项目必然会有多个 .obj 文件,并且这些文件之间存在各种联系,如函数调用等。链接器做的事就是把目标文件和所用的一些库链接在一起形成一个完整的可执行文件。Other Linker Flags 设置的值实际上就是 ld 命令执行时后面所加的参数。下面介绍3个常用参数:

参数 描述
-ObjC 链接器会把静态库中所有的 Objective-C 类和分类都加载到最后的可执行文件中
-all_load 链接器会让所有找到的目标文件都加载到可执行文件中
-force_load 需要指定要进行全部加载的库文件的路径

注意:千万不要随便使用 -all_load 这个参数!假如你使用了不止一个静态库,然后又使用了这个参数,那么很有可能会遇到 ld: duplicate symbol 错误,因为不同的库文件里面可能会有相同的目标文件,所以建议在遇到 -ObjC 失效的情况下使用 -force_load 参数。

Bundle

什么是 bundle

Bundle 可以理解为一个资源目录,并包含了程序中会用到的资源,如图像、声音、编译好的代码或 nib 文件等。

创建 bundle

Bundle 创建有两种方式:

简单的创建 bundle

创建一个文件夹,强制重命名该文件夹为 ${yourBundleName}.bundle

通过 Xcode 创建 bundle

步骤1:新建一个项目,依次点击 TARGETS → + → mac OS → Framework & Library → Bundle,输入 Product Name即建立出 bundle 工程;

步骤2:在 bundle 目录下添加需要的资源文件,编译之后在整个项目工程的 Products 文件夹下得到资源文件 bundle 。

这样做默认情况下 bundle 里面的 png 图片会被转为 tiff 的格式。因此在编译前需要做一步设置:找到 bundle 的工程,把 Build Settings 里的 COMBINE_HIDPI_IMAGES 设置为 NO 之后再编译运行。

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

推荐阅读更多精彩内容