作者Talent•C
转载请注明出处
前言
关于Framework制作的教程数不胜数,但是比较老旧,一般都是xcode7或者更早的教程,并且有些教程并不齐全,制作出来的framework库还是存在大大小小的问题,所以我把自己制作framework的过程记录下来,并且使用的是最新的Xcode8环境;
正文
Bitcode是什么?
Bitcode is an intermediate representation of a compiled program. Apps you upload to iTunes Connect that contain bitcode will be compiled and linked on the store. Including bitcode will allow Apple to re-optimize your app binary in the future without the need to submit a new version of your app to the store.
Xcode hides symbols generated during build time by default, so they are not readable by Apple. Only if you choose to include symbols when uploading your app to iTunes Connect would the symbols be sent to Apple. You must include symbols to receive crash reports from Apple.
原文大意:
Bitcode是编译程序的中间表示形式。 您上传到iTunes Connect的包含位代码的应用程序将在商店中进行编译和链接。 包括位代码将允许Apple在将来重新优化您的应用程序二进制文件,而无需将新版本的应用程序提交到商店。默认情况下,Xcode会隐藏在构建时生成的符号,因此它们不可读取。 只有当您将应用程序上传到iTunes Connect时选择包含符号,才能将符号发送给Apple。 您必须包含符号以从Apple收到崩溃报告。
摘自:Apple 开发者文档
bitcode图解
为了更好的理解什么是bitcode,简单介绍一下编译器编译的过程:
1.Lexer: 读入源文件,并将其转化成字符流
2.Parser: 将字符流转换成AST(抽象语法树)
3.Semantic Analysis: 对输入的AST进行语法检查。
4.Code Generation: 代码生成,将AST转换成低层次的IR指令
4.Optimization: 分析IR指令,将其中潜在会拖慢运行速度的指令干掉。
5.AsmPrinter: 通过IR(中间码)生成特定CPU架构的汇编代码
6.Assemble: 将汇编代码转化成二进制
7.Linker: 通常程序会引用其他的二进制文件(.a或者framework),但是这些链接在程序中没有正确的地址,只是个占位符。Linker的工作就是给这些占位符正确的地址。
更多信息请参考The Compiler
一般情况下编译器构架会将上述过程分成前端和后端两部分来处理:
在前后端之间传递的就是IR(中间码),而bitcode就是一种特殊形式的中间码。原本前后端的工作都是在本地LLVM中完成,虽然Apple没有给出具体的Bitcode实现,但是通过他们的文档可以猜测,是将一部分后端的工作移到了服务器进行。从Xcode上传IR到服务器,服务器来真对不同的机型进行后续操作。从而达到真对不同机型生成对应指令集的二进制,而减小报体积的目的。
开始制作framework
1.首先新建一个项目,选择 Cocoa touch Framework
取名”TalentCFor-framework”
2.将要封装成framework的代码拖入工程
3.设置Build Setting
选择工程文件> target 第一项>Build Setting
(1).Dead Code Stripping: 设置为 NO, 网上对此项的解释如下,大致意思是如果开启此项就会对代码中的”dead”、”unreachable”的代码过滤,不过这个开关是否关闭,似乎没有多大影响,不过为了完整还原framework中的代码,将此项关闭也未曾不可。
The resulting executable will not include any “dead” or unreachable code。
(2).Link With Standard Libraries: 设置为 NO 可能是为了避免重复链接
(3).Mach-O Type: 设为 Static Library framework可以是动态库也可以是静态库,对于系统的framework是动态库,而用户制作的framework只能是静态库。
然后将需要公开的头文件从_Project中拖入 Public,至于是否需要将私有的头文件拖入 Private,我觉得直接放在Project中即可,若是Private中有头文件,打包以后的framework中会多出一个Private的文件夹包含着放入Private的头文件,不过我觉得如果是私有最好还是不要让别人看到。 这里为了给大家演示则将Utils这个工具类放入Private。
为了对一些特殊机型的支持,添加 armv7s 架构,当然不添加也没什么问题,只有5和5c使用了此架构。
注意,注意,注意 重要的事说三遍… 以下 (4)、(5) 很重要 很重要 很重要
Bitcode是苹果在Xcode7及以后推出的新功能。用于代码的二次编译,针对CPU进行优化,编译工作由苹果AppStore后台来完成。
针对iOS是可选项,默认打开。watchOS 和 tvOS 是必选项
(4).Build Active Architecture only: 设置为 NO ,设为YES,导致其编译时只生成当前机器的框架,将其设置为NO后,发现用模拟器编译后生成的framework同时包含x86_64和i386架构。
(5).所以需要打开库工程的此选项并加上 -fembed-bitcode 参数
到此全部设置完毕开始编译 !!!
编译成功 查看编译后的framework库
打开终端查看模拟器的framework 与 真机的 framework 支持的架构
查看真机环境的framework: lipo -info lipo -info /Users/chuliangliang/Library/Developer/Xcode/DerivedData/TalentCFor-framework-arwwimdmqumeihfeafwteozpdlws/Build/Products/Debug-iphoneos/TalentC.framework/TalentC
查看模拟器的framework: lipo -info /Users/chuliangliang/Library/Developer/Xcode/DerivedData/TalentCFor-framework-arwwimdmqumeihfeafwteozpdlws/Build/Products/Debug-iphonesimulator/TalentC.framework/TalentC
制作通用库
终端执行
lipo -create /Users/chuliangliang/Library/Developer/Xcode/DerivedData/TalentCFor-framework-arwwimdmqumeihfeafwteozpdlws/Build/Products/Debug-iphoneos/TalentC.framework/TalentC /Users/chuliangliang/Library/Developer/Xcode/DerivedData/TalentCFor-framework-arwwimdmqumeihfeafwteozpdlws/Build/Products/Debug-iphonesimulator/TalentC.framework/TalentC -output /Users/chuliangliang/Library/Developer/Xcode/DerivedData/TalentCFor-framework-arwwimdmqumeihfeafwteozpdlws/Build/Products/All/TalentC
将…Products/All/TalentC 的 TalentC 文件替换 …/Products/Debug-iphoneos/TalentC.framework/TalentC 中的 TalentC 文件, 至此通用的framework就制作完毕了, 底部有工程下载地址;
实际结果均以最终打包结果为准,此framework经过实际打包app是完全可以通过的!!!
总结
架构: 对于模拟器来说4s和5的模架构是i386的32位架构,5s至今是x86_64的64位架构。对于真机来说3GS~4s是armv7架构,5和5c是armv7s架构,5s至今是arm64架构
静态库: 链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝
动态库: 链接时不会拷贝至可执行文件中,运行时动态加载进内存,供程序调用,只加载一次,多个程序可以共用
本次演示Demo