iOS-SDK开发之制作自己的静态库 .framework和.a文件

先来看几个概念定义:

  • 什么是库?
    库是共享程序代码的方式,一般分为静态库和动态库。
  • 静态库和动态库的区别?
    静态库:链接时完整地拷贝至可执行文件中,呗多次使用就有多分冗余拷贝
    动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
  • iOS里静态库的形式?
    .a 和 .framework
  • iOS动态库的形式?
    .dylib 和 .framework
  • framework为什么既是静态库有事动态库?
    系统的.framework是动态库,我们自己建立的.framework是静态库
  • .a 和 .framework有什么区别?
    .a 是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件
    .a 文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用
    .a + .h +sourceFile = .framework
  • 为什么使用静态库?
    方便共享代码,便于合理使用。(懒逼格高)
    实现iOS程序的模块化。可以把固定的业务模块化成静态库。(懒高大上)
    和别人分享你的代码库,但不想让别人看到你代码的实现。(怕被喷)
    开发第三方SDK的需要。

我们可以看出.a的封装和.framework的封装差不多,也有模拟器和真机合并的过程,通过上边的图片我们可以看出.a 和.framework的区别,就是.a+.h+soureFile=.framework。可以看出我们直接封装.framework其实是最好的。不啰嗦了,先来看看.a文件是怎么封装的

一 .a文件的封装

(一)创建一新工程TestSDK,选择Framework & Library中的 Cocoa Touch Static Library,如图1

图1.jpg
工程中会看到TestSDK.h和TestSDK.m文件,干掉TestSDK.m文件到垃圾桶
只留下.h文件就可以。
(二)创建你要封装的模块,由于本文主要是讲述制作流程这里我直接拖入一个模块如图2:
图2.jpg
Add to targets 一定要勾选!一定要勾选!一定要勾选!
在TestSDK.h中引入你的控件的头文件ChannelAlert.h即可。
(三)分别选择模拟器和真机编译工程,在Products下会生成.a文件,show in finder会发现如图3两个.a文件
图3.jpg

iphoneos 适用于真机,iphonesimulator适用于模拟器。打开终端合并两个文件成为通用版本,命令

lipo -create
模拟器.a文件目录  
真机.a文件目录
-output  输出目录/文件

如图4:
图4.jpg

(嘿嘿是不是很红)
看到libTestSDK.a了吧,这就是通用版本的.a文件
(四)使用方法:

将libTestSDK.a,ChannelAlert.h,TestSDK.h放到一个文件夹下,取个名字如图5:
图5.jpg

将此文件夹拖入到你需要使用的工程中,在需要的地方导入头文件TestSDK.h如图6:
图6.jpg

功能按照你正常的使用方式就可以了。看看我的效果
图7.jpg

到此简单的.a文件制作完成了,下面我们来看看更好的framework是如何制作的

二 .framework文件的封装

(一)创建工程TestFramework,如图F1:


F1.jpg

(二)创建自己的类,Tool.h,Tool.m,如图F2:
F2.jpg

如果有依赖库就要添加依赖库(本文重点是流程,这里就不多加赘述)。在TestFramework.h中#import "Tool.h"。
(三)在Build Phases->Headers中设置你要暴露的接口,主要设置Public和Private,这里我把Tool.h移动到了Public中如图:
F3.png

选择模拟器和真机,分别编Command+B一次,

在工程目录Products show in Finder可以看到两个framework分别对应模拟器和真机如图:
F4.jpg

iphoneos 对应的是真机,iphonesimulator对应的模拟器

下面我们将两个framework合并,要用到脚本语言

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 "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
#open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi

如图:
F5.png

在4位置添加上面的脚本,然后Run(xcode左上角的黑三角)之后会弹框在Products里面就可以看到TestFramework.framework了。
(四)使用方法

将改TestFramework.framework拖入到你需要的工程中(如过有依赖库,记得添加依赖库),因为需要让编译器提前编译这个二进制文件。进入General->Embedded Binaries,将加入的framework添加上去。如图:
F6.jpg

在你需要的地方导入头文件:如图
屏幕快照 2018-04-26 17.18.02.png

至此,简单的.framework就算是制作完成了。这也仅是一个流程,毕竟framework博大精深。写一点注意事项吧
1、.h文件的外漏一定要保证是自己的想要外漏的。不想外漏的就别外漏了。
2、开始打包的时候,一定要在选中模拟器和选中真机上边分别编译一次, 我觉得之前在家里没有真机的时候编译的好像不对。
3、终端也可以合并(这里就不写了,有兴趣的可以自己搜一搜),在终端上边合并的时候可能是error并生成一个.lipo文件,不要怕,大胆修改成同名的不挂后缀的同名文件。
4、调用的时候分清楚是类方法还是实例方法,方便调用。
5、在制作framework或者lib的时候,如果使用了category,则使用改FMWK的程序运行时会crash,此时需要在该工程中 other linker flags添加两个参数 -ObjC -all_load。(这点没有亲测)
6、带有图片资源的需要把图片打包成Bundle文件,和framework一起拷贝到相应的项目中。
7、公开的类中如果引用的private的类,打包以后对外会报错,找不到那个private的类,可以把那个private的.h放到(也没亲测)
8、**namespace 冲突。**静态库用了某第三方库,项目也用了同样的第三方库,在编译的时候就会有 duplicate symbol 错误,因为有两份同样的第三方库。解决办法就是把用到的第三方库加上自定义前缀,包括类名、delegate 协议、常量名,尤其需要注意 Category 的方法名要修改。
9、封装静态库的时候应尽量避免引入重量级第三方库,**多自己进行封装**。
10、一个静态库要**有自己独有的前缀**,所有类名、常量等都要加同样的前缀。
11、**真机+模拟器支持**。(和第2条意思一样)Xcode 默认只会用当前环境(真机或模拟器)生成静态库,这样的 SDK 不方便其他项目开发时调试。解决办法就是通过脚本生成一份通用库,build_universal_library.sh,via SO.
12、**文档**。静态库的方便是使用者直接拿你提供的方法来用,无需关注具体实现;不方便在于看不到实现,出现问题无法排查,因此需要把 SDK 的版本、更新历史、使用、FAQ 等写成文档,方便使用,也显得 SDK 比较正式规范。
13、图片等资源文件用 **bundle** 方式打包。一个简单制作 bundle 的方法:新建文件夹,重命名为 YourSDK.bundle,然后 Show Package Contents 打开,加入图片。使用图片的时候需要指明 bundle: [UIImage imageNamed:@"YourSDK.bundle/img.png"]。也可以用 Target 方式制作 bundle。
14、如果 SDK 有用到 **Category**,注意项目设置 Other Linker Flags 添加 -ObjC。

编译过程:
从C代码到可执行文件经历的步骤是:源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件

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

下面逐个介绍3个常用参数:
-ObjC:加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中

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

-force_load:所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载

研究不深,欢迎各位来指点。

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

推荐阅读更多精彩内容