作为iOS开发者,想必我们都用过Apple自带的或者第三方开发的Framework(框架),比如,当我们开发音视频功能时,需要在Xcode的TARGETS -> General -> Linked Frameworks and Libraries内添加苹果自带的框架AudiToolBox.framework与AVFoundation.framework,又比如,我们使用科大讯飞的语音SDK时,需要下载他们提供的框架iflyMSC.framework,并添加至Linked Frameworks and Libraries内。
如果我们作为第三方开发者,需要将自己开发的iOS工具包或者SDK分享给其他开发者,而又不想公开源码,那么这时候就需要将iOS源码编译成框架后发布出来,我们将这个过程通俗地称为“打包”。但“打包”并不容易,很多开发者包括我一开始都无从下手,Google了很多英文博客才搞定。好记心不如烂笔头,为了便于自己下次再次打包,同时为了方便有打包需求的其他开发者,故制作该教程指导大家如何使用Xcode编译iOS Framework。
1、新建静态库工程
选择iOS -> Framework & Library -> Cocoa Touch Static Library
很多第三方SDK,如微信、新浪微博、Google AdMob选择的是Static iOS Framework,最终编译出来是类似于libXXX.a的静态库文件,这种方式的缺点在于libXXX.a静态库文件与公开的头文件是分开的,不便于管理。如果选择Cocoa Touch Static Library,最终编译出来的是一个完整的Framework Bundle文件,它类似于一个压缩包文件,会整合编译出来的静态库与公开的头文件,便于管理与使用。
2、为你的工程取个名字
这个演示用Framework最终想实现的功能是对外提供一个helloFramework接口,其他工程加载这个框架后调用该接口弹出警告框并显示“Hello Framework”,故将工程名称设置为HelloFramework,组织名称跟公司名称你都可以根据自己的需求来设置。如果不是十分想突出你产品或公司的品牌价值的话,这些随意设置即可。
3、为你的工程选择一个存储位置
随意选择,方便找到即可,我这里选择的是桌面。
4、删除Xcode向导自动生成的文件
如上图所示,有4处需要删除,删除①、②两处时按下图所示,将其删除至回收站即可。
删除后所剩文件如下:
5、删除Xcode自动生成的配置选项
在Xcode内按快捷键Command+Shift+<或者通过Product->Scheme->Edit Scheme…进入配置编辑界面,点击Manage Scheme..,在如下界面内删除自动生成的HelloFramework配置,删除完毕后点击OK返回。
6、新增一个Target
步骤1~5只是利用Xcode向导新建了一个iOS静态库工程,自动生成了一系列配置,然后删除了其自动生成的基本文件与配置,而接下来才开始新建iOS框架工作。我个人的理解是,Xcode只为iOS提供了生成静态库的向导,没有提供生成Bundle的向导,但Xcode为OS X提供了生成Bundle的向导,所以我们只能利用Xcode为OS X提供的新建Bundle向导来为iOS新建Bundle,最终将这个Bundle转化为Framework。
类似与步骤2,为你的框架(新建的Target)取个名字,这将是最终生成的框架的文件名,我这里取为“HelloFramework”,组织跟公司名沿用之前新建工程时设置的。
7、修改步骤6中新建的Target的“Build Setting”
(1)修改Architectures(架构)内的配置
选择Standard architectures、选择Latest iOS、Build Active Architecture Only选No。
(2)修改Deployment(部署)内的配置
OS X部署目标选择OS X默认编译器,让Xcode自动判断OS X系统版本,为了兼容iPhone跟iPad,目标设备两者都选,为了兼容尽可能多的iOS版本,iOS部署目标选择可选的最低版本,我这里可选的最低版本是iOS 4.3。
(3)修改Linking(链接)内的配置
优化代码选项设置为No,链接标准库选项设置为No,指定目标文件的链接格式为重定位方式。
(4)修改Packaging(打包)内的配置
打包的默认后缀名是bundle,将其更改为framework。
8、修改步骤6中新建的Target的”Info”
Bundle OS Type code选项默认为BNDL,改为FMWK,原理同步骤7中的(4),将默认的Bundle更新为Framework。
9、注释Xcode自动生成的预编译头文件
10、为新建的框架添加类(简单演示,故只新建一个类,大型工程需要多少类就新建多少类)
我这里新建一个名为“HelloFramework”的类。
11、在新添加的类中完成你要实现的功能
由于是简单演示,故只实现一个弹出警告框显示“Hello Framework”的对外接口。分别在HelloFramework.m中实现hello函数,在HelloFramework.h文件中给以声明。
12、添加你要对外公开的头文件
13、插入一个步骤
由于步骤4中忘了删除Frameworks内的UIKit.framework,直接编译会报错,故在此更正步骤4的截图。
①~④步已经在步骤4中完成了,这里只需要补上第⑤步。
14、编译真机跟模拟器可以通用的框架
首先,添加一个集合器Aggregate,命名为buildUniversalFramework(编译真机跟模拟器通用框架)。
然后,新建一个编译脚本,写入编译指令。
在Products目录内存放编译生成的框架,框架名称由第2行FMK_NAME=来指定。
不难看出,上侧编译脚本的任务是在工程文件所在目录内新建一个Products目录,然后分别编译真机跟模拟器的框架,再把真机框架内的文件拷贝至Products目录下,最后用lipo命令将真机框架与模拟器框架合并到Products目录内下,同时删除编译时自动生成的build目录。
上侧的编译脚本如下,大家使用时务必修改第2行FMK_NAME=后面的框架名称:
# Sets the target folders and the final framework product. FMK_NAME=HelloFramework # Install dir will be the final output to the framework. # The following line create it in the root folder of the current project. INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework # Working dir will be deleted after the framework creation. WRK_DIR=build DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework # Building both architectures. xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator # Cleaning the oldest. if [ -d "${INSTALL_DIR}" ] then rm -rf "${INSTALL_DIR}" fi # Creates and renews the final product folder. mkdir -p "${INSTALL_DIR}" # Copies the headers and resources files to the final product folder. cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/" # Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product. lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}" rm -r "${WRK_DIR}"
最后,编译真机模拟器通用框架。
在工程文件所在目录下的Products目录内就能找到我们刚刚编译成功的真机模拟器通用框架。
到此,整个框架编译过程也完毕了。
15、附加:测试框架
(1)新建一个iOS Single View Application工程,命名为test,存在Desktop(桌面)上。
(2)将HelloFramework框架添加到新工程内。
(3)在test工程启动后调用HelloFramework框架对外提供的hello接口,选择一个模拟器,点击运行。
(4)虽然运行成了,但我们发现Xcode提示了警告。
这是由于我们编译的框架是静态库,运行崩溃时不会自动生成dSYM文件,只需要在新工程Build Setting -> Build Options下的Debug Information Format修改为DWARF即可。
再次运行,Xcode不再提示警告。
16、结束语
其实编译类似于libXXX.a的iOS静态库框架,采用Xcode自带的向导,不必进行如上这么多复杂的操作即可完成。国内绝大多数公司提供的iOS框架也是似于libXXX.a的iOS静态库附加头文件。之所以这篇教程非要指导大家将框架编译成类似于XXX.framework的形式,也是为了跟苹果自带的绝大多数框架呈现形式保持一致,同时也让开发者简单拖动这个XXX.framework到工程就能完成对框架的加载。
整篇教程,个人觉得比较有技术含量的是步骤14,尤其是14中利用Aggregate自动合并真机框架与模拟器框架,虽然新建工程时写这么多脚本语言比较麻烦,但一旦写完后,以后每次打包就相当方便了,不必再去Terminal(终端)内合并真机框架与模拟器框架,既能省力,又可以避免不少因为粗心而造成的错误。
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。