iOS封装功能生成 .framework

前言

      若是你想将你开发的控件与别人分享,一种方法是直接提供源代码文件。然而,这种方法并非很优雅。它会暴露全部的实现细节,而这些实现你可能并不想开源出来。此外,开发者也可能并不想看到你的全部代码,由于他们可能仅仅但愿将你的这份漂亮代码的一部分植入本身的应用中。html

      另外一种方法是将你的代码编译成静态库(library),让其余开发者添加到本身的项目中。然而,这须要你一并公布全部的公开的头文件,实在是很是不方便。ios

你须要一种简单的方法来编译你的代码,这种方法应该使得你的代码易分享,而且在多个工程中易复用。你须要的是一种方法来打包你的静态库,将全部的头文件放到一个单元中,这样你就能够马上将其加入到你的项目中并使用。xcode

      OS X完美地支持这一点,由于Xcode就提供了一个项目模板,包含着默认构建目标(target)和能够容纳相似于图片、声音、字体等资源的文件。你能够为iOS建立Framework,不过这是一个比较复杂的手工活,若是你跟着教程走,你将学到怎么样跨过路障,顺利地完成Framework的建立。iphone

比较

能够参考这篇文章.a和.framework.a和.framework的区别函数


 

咱们能够看出.a的封装和.framework的封装差很少,也有模拟器和真机合并的过程,经过上边的图片咱们能够看出.a 和.framework的区别,就是.a+.h+soureFile=.framework。能够看出咱们直接封装.framework实际上是最好的。那么咱们就来看看framework怎么封装的。测试

另外关于.a的封装你们能够参考iOS如何生成.a文件字体

目标

      本文将基于Xcode7建立一个简单的工程,经过两种方法来教你们如何制做一个本身的framework,目的就是简单易学的制做framework。这种方法可使得你的代码易分享,在多个工程中复用,而且能够隐藏实现细节控制公开的头文件ui

步骤

一、打开Xcode,新建工程。spa

不要选择“Application”,选择“Framework & Library”。选择第一个,而后Next。.net


 

二、建立功能类。

这里我建立一个继承自NSObject的SayHello类

三、实现功能。

在新建立的类里面声明方法并实现。这里我写一个sayHello的方法,以便后面测试使用。


 

四、更改参数

在TARGETS下选中工程,在Build Settings下更改几个参数。


 

五、增长armv7s

  在Architectures下增长armv7s,并选中。将Build Active Architecture Only 设置为NO。


 

六、设置Headers

将你要公开的头文件拖至Public下,要隐藏的放在Private或者Project下,固然,隐藏的头文件就没法再被引用。


 

而后须要在Test.h(必须是公开的,不然没法引用)中将你全部要公开的.h引入。


 

 

 

打包Framework

第一种方法

1.选中模拟器,编译程序

2.选中测试机,编译程序

3.在finder中找到framework文件


选中图中所标示的framework,而后右键show in finder。

找到下图中所示的Test文件,一个是Debug-iphoneos(真机)下的,一个是Debug-iphonesimulator(模拟器)下的。


 

4.经过终端命令将两个framework合为一个模拟器和真机均可使用的framework。

打开控制台输入 lipo -create iphoneos下frameworkTest的路径 simulator下frameworkTest的路径 -output 新的路径,这样就完成了模拟器和真机版本的合并,新路径下的frameworkTest就是你合并后的文件,将这个文件名字改为和你未合并以前的Test同样的名字,放到framework文件夹下,替换掉原来的frameworkTest文件。

上边说的乱糟糟的,看不清楚,这里给你们解释一下,看下边的图:打开终端手动输入画红线的lipo -create命令,而后绿线是iphoneos下frameworkTest的路径(找到iphoneos下frameworkTest的文件,拖拽进来),会自动有空格,紫线是simulator下frameworkTest的路径(一样找到simulator下frameworkTest的文件,拖拽进来),也会自动有空格,而后输入-output,而后敲空格,在引入一个新的路径(拖拽进一个新的路径),最后敲回车。这样就完成合并了。


 

上面这段命令就是把真机和模拟器的frameworkTest合并成一个MyNewFrameworktest文件并存放在桌面上的New文件夹下。

这里咱们合并的时候会遇到一个error,这是啥缘由还真不知道,可是会在和咱们-output的文件夹路径并列的地方生成一个.lipo文件,这个.lipo文件咱们下边会说到。


 

 

注意:合并完成后会出现一个以下图的.lipo格式的文件。


 

这TM是啥,不是应该出现一个相似下图的吗?不该该后缀什么也没有吗?怎么后缀会是.lipo,这是什么文件啊?!


 

咱们的操做是按照人家说的把合成后的文件名字改为MyFrameworkTest替换原来的。并且,把后缀.lipo去掉!

在按照上述说的,替换了原来的。

而后就能够进行下一步了。

5.将修改后的framework拷贝出来保存,这就是咱们最终制做的framework。

第二种方法

一、选中TARGETS下的工程,点击上方的Editor,选择Add Target建立一个Aggregate.


 

二、选择Other下的Aggregate,点击Next建立。


 

三、嵌入脚本。选中刚刚建立的Aggregate,而后选中右侧的Build Phases,点击左下方加号,选择New Run Script Phase


 

将这段脚本复制进去:

# Sets the target folders and the finalframework product.# 若是工程名称和Framework的Target名称不同的话,要自定义FMKNAME# 例如: FMK_NAME = "MyFramework"FMK_NAME=${PROJECT_NAME}# Install dir will be the final output tothe framework.# The following line create it in the rootfolder of the current project.  INSTALL_DIR=${SRCROOT}/Products/$      {FMK_NAME}.framework# Working dir will be deleted after theframework creation.  WRK_DIR=build  DEVICE_DIR=${WRK_DIR}/Release-iphoneos/$                        {FMK_NAME}.framework  SIMULATOR_DIR=${WRK_DIR}/Release-  iphonesimulator/${FMK_NAME}.framework# -configuration ${CONFIGURATION}# Clean and Building both architectures.xcodebuild -configuration"Release"-target"${FMK_NAME}"-sdk iphoneos clean build  xcodebuild -configuration"Release"-target"${FMK_NAME}"-sdk iphonesimulator clean          build# Cleaning the oldest.if[-d"${INSTALL_DIR}"]thenrm -rf"${INSTALL_DIR}"fimkdir -p"${INSTALL_DIR}"cp -R"${DEVICE_DIR}/""${INSTALL_DIR}/"# Uses the Lipo Tool to merge both binaryfiles (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}"open"${INSTALL_DIR}"

这里有一个误区,就是复制上边的这段脚本的时候,会在咱们指望的效果里面多了几个回车,这几个回车是致命的,若是不删除回车,会报出以下的错误:


 

 

最后的格式以下图,尽可能一个回车也不能错:


 

经过第一种方法中“把真机和模拟器的frameworkTest合并成一个”的过程和上边的脚本语言比较,咱们能够发现其实二者异路同归,两个方法里面同时用到了“lipo -create  xxx”和“-output xxx”,不一样的地方是第一种方法须要咱们本身真机和模拟器分别变异一遍,并且须要咱们把framework的路径拖进去,相比而言第二种方法比较简单。

四、编译。如图所示,command+B编译。这里Generic iOS Device的意思是“iOS通用设备”,大概就是说模拟器和真机都能用。


 

五、编译成功后会自动跳出一个finder,保存这个.framework,这就是咱们须要的framework。


 

至此,两种打包framework的方法介绍完成!

 

 

最后就是用咱们的Framework了,倒入另外一个Xcode中,咱们打开这个framework看看,发现只有Headers,里面有两个.h,其中一个是咱们以前添加的FrameworkDemo.h文件,另外一个就是咱们的SayHello.h 。


 

而后引入头文件:


 

因为咱们测试的方法是实例方法,那么咱们实例化一个实例对象,而后就可让这个实例对象调取相应的方法了:


 

至此,完成Framework的制做和使用。

 

总结

最后须要注意的是:

一、.h文件的外漏必定要保证是本身的想要外漏的。不想外漏的就别外漏了。

二、开始打包的时候,必定要在选中模拟器和选中真机上边分别编译一次, 我以为以前在家里没有真机的时候编译的好像不对。

三、在终端上边合并的时候多是error并生成一个.lipo文件,不要怕,大胆修改为同名的不挂后缀的同名文件。

四、调用的时候分清楚是类方法仍是实例方法,方便调用。

五、在制做framework或者lib的时候,若是使用了category,则使用改FMWK的程序运行时会crash,此时须要在该工程中 other linker flags添加两个参数 -ObjC -all_load。(这点没有亲测)

六、带有图片资源的须要把图片打包成Bundle文件,和framework一块儿拷贝到相应的项目中。

七、公开的类中若是引用的private的类,打包之后对外会报错,找不到那个private的类,能够把那个private的.h放到(也没亲测)

八、namespace 冲突。静态库用了某第三方库,项目也用了一样的第三方库,在编译的时候就会有 duplicate symbol 错误,由于有两份一样的第三方库。解决办法就是把用到的第三方库加上自定义前缀,包括类名、delegate 协议、常量名,尤为须要注意 Category 的方法名要修改。

九、封装静态库的时候应尽可能避免引入重量级第三方库,多本身进行封装

十、一个静态库要有本身独有的前缀,全部类名、常量等都要加一样的前缀。

十一、真机+模拟器支持。(和第2条意思同样)Xcode 默认只会用当前环境(真机或模拟器)生成静态库,这样的 SDK 不方便其余项目开发时调试。解决办法就是经过脚本生成一份通用库,build_universal_library.sh,via SO.

十二、文档。静态库的方即是使用者直接拿你提供的方法来用,无需关注具体实现;不方便在于看不到实现,出现问题没法排查,所以须要把 SDK 的版本、更新历史、使用、FAQ 等写成文档,方便使用,也显得 SDK 比较正式规范。

1三、图片等资源文件用 bundle 方式打包。一个简单制做 bundle 的方法:新建文件夹,重命名为 YourSDK.bundle,而后 Show Package Contents 打开,加入图片。使用图片的时候须要指明 bundle: [UIImage imageNamed:@"YourSDK.bundle/img.png"]。也能够用 Target 方式制做 bundle,好比 iOS Library With Resourceshttp://www.galloway.me.uk/tutorials/ios-library-with-resources/.

1四、若是 SDK 有用到 Category,注意项目设置 Other Linker Flags 添加 -ObjC。(后边介绍了-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须要指定要进行所有加载的库文件的路径,这样的话,你就只是彻底加载了一个库文件,不影响其他库文件的按需加载

 

后期会试着把贝塞尔画饼的demo封装成framework,另外可能会增长Bundle文件的生成方法。

参考自一、iOS-制做Framework(最新)

          二、iOS--建立你本身的Framework

 

最后,哪里不对的地方能够给我留言,我会及时改进的,谢谢你们。

做者:和珏猫 连接:http://www.jianshu.com/p/87dbf57cfe4a 來源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
相关文章
相关标签/搜索