又到周五了,明天又是一个美好的周末,今天就好好总结一下Xcode11有关framework的打包问题以及Bundle打包的问题。
误区①:.framework是动态库,.a是静态库:
Framework是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。
Framework只是一种打包方式,其本身和静态、动态无关
误区②:有人说“自定义的动态库苹果审核不通过”,或者说”不允许打包framework动态库“
在 iOS 8 / iOS6之前,iOS 平台不支持使用动态 Framework,开发者可以使用的 Framework 只有系统的framework,这种限制可能是出于安全的考虑。
换一个角度讲,因为 iOS 应用都是运行在沙盒当中,不同的程序之间不能共享代码,同时动态下载代码又是被苹果明令禁止的,没办法发挥出动态库的优势,实际上动态库也就没有存在的必要了
但是用framework确实比用.a加头文件的方式简单,所以这个时期开发者用了很多技巧来制作framework,这就有了Fake Framework 和 Real Framework的区分
在 iOS 8 / iOS6后,iOS平台添加了动态库的支持,同时, Xcode 6 也原生自带了 Framework 支持。
在Xcode11的framework工程里 Build Setting -> Mach-O Type 这个选项下,有着这五个类型。而如果我们创建一个 Framework,不手动修改的默认配置即为 Dynamic Library(动态库)。
文件类型 | 描述 |
---|---|
Executable | 可执行二进制文件 |
Dynamic Library | 动态库 |
Bundle | 非独立二进制文件,显式加载 |
Static Library | 静态库 |
Relocatable Object File | 可重定位的目标文件,中间结果 |
一般情况(大多数)主要考虑的是要使用 Dynamic Library(动态库)还是 Static Library(静态库)。但是极少有人真的考虑过是否要使用另外的三种类型来制作 SDK。但是我就遇到了第五种的,死活编译不过,最终改用Static Library立马成功。具体错误就不得而知(提示我9000多个重复定义,但是打别的包就没问题)。
接下来,先介绍一下这几个类型的作用及区别。
创建一个 Framework 项目,更改 Build Setting -> Mach-O Type 为 Executable。command
+B
编译一下:
clang: error: invalid argument '-compatibility_version 1' only allowed with '-dynamiclib'
clang: error: invalid argument '-current_version 1' only allowed with '-dynamiclib'
那就更改一下设置,删除默认的 -compatibility_version
和 -current_version 两个配置。再编译发现:
ld: entry point (_main) undefined. for architecture x86_64
这个问题是因为,编译时候选择的机型为模拟机,文章最后,我会对这个iOS架构进行一下补充。
到这里,这个方式就算是结束了,因为可执行文件会直接被系统执行,所以需要一个 _main
函数入口,而需要创建和使用的 SDK 明显是不符合这个条件的。
创建一个 Framework 项目,更改 BuildSetting -> Mach-O Type 为 Bundle。同样修改 -compatibility_version
和 -current_version
两个配置之后,command + B
编译成功。
成功了就来使用一下它,新建一个app工程,将 Bundle 用资源加载的方式(Build Phases -> Copy Bundle Resources)进行添加。然后在 ViewController 里面写入下面的语句。
NSString *bundleString = [[NSBundle mainBundle] pathForResource:@"name" ofType:@"framework"];
NSBundle *SDKBundle = [NSBundle bundleWithPath:bundleString];
[SDKBundle load];
运行发现,成功了,那framework类型的Bundle与后面即将介绍的Bundle工程有什么区别呢?这个希望有人能够补充一下。
我在给demo进行更新迭代时候,遇到了这个类型的framework,更改底层后,死活打包不成功,无奈改用了Static Library。创建一个 Framework 项目,更改 BuildSetting -> Mach-O Type 为 Relocatable Object File。同样修改了 -compatibility_version
和 -current_version 两个配置之后。CMD + B 编译可能出现如下错误:
ld: -r and -dead_strip cannot be used together
移除 Dead Code Stripping后继续编译:
d: -rpath can only be used when creating a dynamic final linked image
把 -rpath 移除后继续编译,成功。(在我的工程里就提示我9000多个重复定义,一直解决不掉)。
同样,运用刚刚的工程,加载用一下,发现正常。
这就是正常的动态库打包了,导入需要打包的工程,在系统生成的.h文件中添加你需要暴露出去的头文件,同时在Build->Phases中添加暴露的头文件。
打包的版本问题这里就不再提及了,图片过后会补充。
创建一个 Framework 项目,更改 BuildSetting -> Mach-O Type 为 Static Library。在other linker flag 中添加-ObjC,更改一下最低支持的iOS版本,Defines Module设置为NO。
再将要打包的工程文件都导入进来,同时对头文件的暴露以及添加#import问题就不再提及了。方式很简单,图片过后补充。
上边介绍了如何去打包不同类型的framework,那么对于最常用的动态库与静态库类型我们如何去判断呢。
file
命令,file xx 注释:xx为.framwork下的二进制文件 进入Build Setting中
BaseSDK 改为iOS
Build Active Architecture Only 改为Yes
Supported Platform 设置为iOS
搜索target,将iOS Deployment Target和macOS Deployment Target设置为最低。
COMBINE_HIDPI_IMAGES 设置为 “NO”
Enable Bitcode 设置为NO
好了,进行痛快的打包吧,注意,Bundle是非执行文件,只适合放资源,例如图片、音频、模型等。
NSBundle *FACESDK_BUNDLE_Model = [[NSBundle alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"Bundle文件名" ofType:nil]];
NSString *deteModelPath = [FACESDK_BUNDLE_Model pathForResource:@"调用的文件名" ofType:@""];
打包了动态库,导入工程中发现程序直接能编译通过,但是运行时候crash,并且没有错误信息,内存定位在: in __abort_with_payload ()
问题
问题原因: Xcode11工程->Build Phases 中没有 embedded binaries 对应的framework 导致的这个问题。
解决方法: xcode11中,在General下,已经没有“Embedded Binaries",这个选项,多出了如下的界面,要想实现和Embedded Binaries一样的添加库,需要点击+号添加framework,然后选择embed&sign,就可以了
这时候就可以看到Build Phases下新增了一个embed framework。
iOS的arm架构
模拟机:
真机:
Armv6:
Armv7:
Armv7s:
Arm64: