创建Relocatable Object File类型的framework静态库工程以及使用静态库

写在前面

过程有点长,但是比较细节,看官各取所需。

创建静态库工程

可以先了解iOS库 .a与.framework区别,静态库可以分为.a和.framework类型的的文件。Xcode创建的静态库工程,默认编译后获得的静态库文件是.a类型的。

Xcode(9.1)创建分为动态库工程和静态库工程:


创建静态库&动态库.png

而我们又需要.framework类型的(而对bundle类型的TARGETS进行一些设置,即可得到一个输出framework文件的工程)具体操作如下:
1)选择上图的静态库,创建一个静态库工程:

创建一个静态库工程.png

2)因为编译生成.a文件,所以删除默认的TRAGETS,后面重新添加一个bundle类型的即可。
删除默认TARGETS.png

3)有些教程说,在Product->Scheme->Manage Schemes中,需要删除关联的build项(其实只要新建的TARGETS的名称相同,是不用删除的,只要新建了,就会重新关联上):
删除build关联项.png

4)删除工程文件:


删除工程文件.png

5)这个时候可以新建一个bundle类型的TARGETS了(注意此处是bundle是属于macOS类型的,后续需要一些设置):

新建bundle类型的TARGETS.png

上面说到,新建的时候使用与工程同名的来创建新的TARGETS,即可不用删除默认的build关联项:
同名的bundle类型TARGETS.png

6)创建完毕,可以看出,bundle在默认情况下,是适用于Mac OS的:


bundle类型默认是适用于Mac OS的.png

因此需要我们对这个bundle类型的TARGETS做一些设置:

创建bundle类型TARGETS的一些设置:

参考:ios 制作自已的framework
1)

Base SDK:Lstest iOS(iOS XX.XX)

2)指令集设置

Architectures:Standard architectures - $(ARCHS_STANDARD)默认之外,添加一个:armv7s
Valid Architectures: armv7 armv7s arm64
具体原因点这里

Architectures相关设置.png

3)Dead Code Stripping用于删除对象文件中不需要加载的符号,减小二进制文件大小(此处为何关闭,我也不知道原因,哪位大神知道的告知一声)

Dead Code Stripping:NO

4)关联标准库(此处关闭,我也不知道原因,哪位大神知道的告知一声)

Link with Standard Libraries:NO

不明真相的设置.png

5)库类型
可参考:浅谈 SDK 开发(一)五种 Mach-O 类型的凛冬之战

Mac-O Type:Relocatable Object File

Mach-o Type.png

6)

在 Packaging 中,将 “Wrapper Extention” 改为“framework”

Wrapper Extension.png

7)

info文件将 “Bundle OS Type Code” 改为 “FMWK”(Framework 的意思)

Bundle OS Type code.png

8)设置SDK支持的最低系统

Build Settings -> Deployment -> iOS Deployment Target 修改具体参数
也可在 General -> Deployment Info -> Deployment Target 处设置,两处设置等效

最低支持系统.png

至此,相关设置完成,即可选择相应环境,Cmd+B 进行编译,以获得framework

编译成功得到framework.png

打开StaticLibObject.framework所在的文件夹,发现这个:
真机模拟器两个文件夹.png

编译后的framework包,是真机环境和模拟器分开的,其实是因为二者所支持的指令集不同,具体得看你的Architectures设置,必要的时候,可以使用lipo命令来合并两个文件成一个文件,使其即支持真机,又支持模拟器。

我们查看,或者合并的文件就是这里面的文件:


需要合并的文件.png

查看真机的(请看我上面的关于Architectures的设置):

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

查看模拟器的:

$ lipo -info WxxStaticLibFramework 
Non-fat file: WxxStaticLibFramework is architecture: x86_64

修改下模拟器的文件名,将其扔进真机的文件夹,执行合并命令
注意咯:最好合并输出的文件与原来的保持名字一致,替换掉原来的文件即可。否则framework中会找不到这个文件!!!(修改了名字还能关联的,有好的办法请告诉我)

合并这两个文件.png
lipo -create 模拟器库 真机库 -output 最终库
$ lipo -create StaticLibObject StaticLibObjectSimulator -output StaticLibLastFramework

查看最终合并的所支持的指令集:

lipo -info StaticLibLastFramework

查询结果:

Architectures in the fat file: StaticLibLastFramework are: x86_64 armv7 armv7s arm64

StaticLibLastFramework已经可以同时用于真机和模拟器了!可是这种方式有点麻烦,每次重新编译,都需要重新合并文件,据说还可以用脚本的方式来合并,待我研究后再补充,这里先占个坑。

framework的使用

framework的使用,无非就是对外暴露.h文件,.h文件中有写好的被人使用的方法。这里抛砖引玉。下面具体说明:
1)新建对外文件,并提供方法 +(void)staticLibSDKTest;

新建对外文件.png

内部方法实现:

+(void)staticLibSDKTest{
    NSLog(@"static lib sdk test method");
}

2)暴露头文件

Build Phases -> + ->New Header Phase

对外暴露文件1.png
添加需要对外暴露的头文件.png
添加需要对外暴露的头文件2.png

注意:添加完默认是归类到Project中,将需要暴露的.h文件,手动拖进Public中即可。

重新编译,即可发现,头文件已经对外暴露了:

头文件已经对外暴露.png

3)创建一个普通工程StaticLibObjectDemo来测试刚刚创建的framework,跑这个工程的时候,注意真机和模拟器的区别!framework的指令集和工程的运行环境要对上!当然,合并执行真机和执行文件的另当别论了。
引入framework的操作这里无需赘叙了:

测试工程中引入framework.png

4)在使用的地方 #import

#import <StaticLibObject/StaticLibSDK.h>

5)调用StaticLibSDK.h中的方法

[StaticLibSDK staticLibSDKTest];

很开心的快捷键Cmd+R,发现报错了:


报错.png

具体错误:framework not found StaticLibObject果然,原先的文件被我删除了,留下的可执行文件是支持模拟器和真机的通用文件StaticLibLastFramework,连文件名都不一样的,难怪找不到:

合并后文件名改了所以找不到.png

上图中的同级中有个info.plist文件,本来以为改动里面的Executable file的名字,就可以了,没想到还是不行!


改变Executable file属性.png

(无奈,重新合并,合并后的文件与原来的同名称):
各自环境编译完成,修改各自的执行文件的名字为:真机的StaticLibObjec1和模拟器的StaticLibObject2,执行合并生成StaticLibObject

$ lipo -create StaticLibObjec1 StaticLibObject2 -output StaticLibObject

然后把StaticLibObject文件丢回去.framework文件夹。
再次编译,即可成功输出:

StaticLibObjectDemo[1980:867317] static lib sdk test method

至此,整个创建和使用bundle类型创建的framework全部完成。

制作静态库的注意事项

从这里搬过来的
1 )注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。

2 )图片资源的处理:两种静态库,一般都是把图片文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把它改名为.bundle就可以了,右键,显示包内容可以向其中添加图片资源。

3 )category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。

4) 如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。

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