iOS SDK(二):Bundle

iOS SDK开发系列:
iOS SDK(一):静态库、动态库创建&接口测试
iOS SDK(二):Bundle
...
待更新..

一、回顾

回顾上一篇,你可以理解并认识到BundleSDK 中的作用:用来存放资源文件。SDKDemo是使用SDK的工程,由图可见,.a / .framework 、.bundle需要导入工程才能使用。

iOS SDK(二):Bundle_第1张图片
iOS SDK工程关系.png

本篇来介绍下,什么是Bundle,如何读取Bundle中的资源。

二、什么是bundle

独立的物理空间,存放各种资源。

App开发与SDK开发

SDK开发中,我们把工程分为 SDK 工程Demo 工程
如果是常规的App开发,我们只会接触到app 工程 ,也就是本文中的Demo 工程 ,也就是有启动入口的能够独立运行的二进制程序。对于Mach-O Type中的Executable类型。

SDK工程 我们开发编译出 .a / .framework ,的二进制库。而 .bundle,包含了各种资源文件(图片、编译过的二进制文件、故事板文件、SSL证书等),使用时需要导入给app 工程SDK工程内部需要实现读取这个bundle中的资源并使用其中的资源。

理清了App开发与SDK开发的区别,下面介绍不同开发读取资源的不同方式。

App开发中

app 工程中,我们将图片放置在工程目录中,可以通过如下方式获取到图片资源:

NSBundle *bundle = [NSBundle mainBundle];
// 或者:
// NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *imagePath = [bundle pathForResource:@"imageName.png" ofType:nil];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

imagePath的路径是这样的:...Demo.app/imageName.png
可以看出 无论是[NSBundle mainBundle]还是[NSBundle bundleForClass:[self class]]指向的bundle都是Demo.app。我们可以把mainBundle 理解为 **.app的内部。

SDK工程中

对于 SDK 工程 读取 SDK.bundle 的资源内容,相当于...Demo.app/imageName.png中间多嵌套一层:
...Demo.app/SDK.bundle/imageName.png
也就是说,我们读取bundle中的资源,其路径是:mainBundle的路径 + 自定义bundle名称 + 文件名。
如下:

NSBundle *mainBundle = [NSBundle mainBundle];
NSString *sdkBundlePath = [mainBundle pathForResource:@"SDK" ofType:@"bundle"];
NSBundle *sdkBundle =  [NSBundle bundleWithPath: sdkBundlePath];
NSString *filePath = [sdkBundle pathForResource:imageName ofType:nil];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];

那么在 SDK工程 中,获取mainBundle,能使用这个吗NSBundle * mainBundle = [NSBundle bundleForClass:[self class]];?毕竟 self 是属于 SDK工程 中的类,这样用的话不就是跨领域了吗?

事实证明是可以的,可以用下图理解。

红色实线框,代表命名空间(独立空间)。
虚线框,代表归属于外部实线框。

对于静态库来说:

iOS SDK(二):Bundle_第2张图片
静态库在app中的关系.png

在iOS工程中,工程内部class是没有命名空间的,同一个工程,不能存在两个同样名字的class,就算用文件夹隔开也不行。因此,可以理解为无论是app工程的class还是SDK工程的class编译链接到同一个命名空间(.app/mainBundle),因此SDK工程中bundleForClass最终获取到的依旧是mainBundle。这也就是为什么,静态库开发中,静态库工程的class、全局变量都需要加上特殊前缀(或者重命名),以避免跟调用SDK的工程产生重复,导致编译错误。

而我们使用的bundle,是独立的命名空间。上图bundle嵌套于mainBundle中。因此读取bundle中的资源,也就需要通过

`mainBundle`的路径 + 自定义`bundle`名称 + 文件名

来读取了。

以上分析,是对于静态库而言。

动态库则是classbundle都各自归属于独立的命名空间,因此通过bundleForClass来获取mainBundle就不适用了。

iOS SDK(二):Bundle_第3张图片
动态库在APP中的关系.png

通过创建一个动态库工程来测试,不清楚如何创建,可参考iOS SDK(一):静态库、动态库创建&接口测试

在动态库的SDK工程中,我们调用bundleForClass

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSLog(@"%@",bundle.bundlePath);

获取到的bundle地址的后段是:

.../Demo.app/Frameworks/SDK.framework

这是动态库跟静态库的区别了,动态库有自己独立的空间。我们通过解压集成动态库的ipa包,也可以直观的发现动态库***.framework就处于.../***.app/Frameworks/的路径下。Frameworks是用于存放动态库的文件夹。而对于静态库,解压ipa之后,是找不到的具体的.framework文件的。

而我们独立于***.frameworkbundle,如果按照静态库的导入方式,则是存在于.../***.app/.bundle路径之下。

既然静态库和动态库,在使用bundleForClass存在如此的差异,使用的时候注意区分。

其实还有一种方式:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *sdkBundlePath = [bundle pathForResource:@"SDK" ofType:@"bundle"];
NSBundle *sdkBundle = [NSBundle bundleWithPath:sdkBundlePath];
NSString *filePath = [sdkBundle pathForResource:@"test" ofType:@"png"];

就是无论静态库还是动态库,我们把自定义的bundle放在***.framework中,这样bundleForClass就通用了,工程导入SDK的时候,也不会漏掉bundle文件。

iOS SDK(二):Bundle_第4张图片
移入

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *sdkBundlePath = [bundle pathForResource:@"SDK" ofType:@"bundle"];
NSBundle *sdkBundle = [NSBundle bundleWithPath:sdkBundlePath];
NSString *filePath = [sdkBundle pathForResource:@"test" ofType:@"png"];

这样得到

  • 动态库的资源路径是:
.../Demo.app/Frameworks/SDK.framework/SDK.bundle/test.png
  • 静态库的资源路径是:
.../Demo.app/SDK.bundle/test.png

完美。

总结

  • 静态库class在宿主工程中没有独立的命名空间,编译后跟宿主工程是链接到一个位置的,假如SDK中使用了第三方库,则需要添加特殊的前缀(或者重命名),防止宿主工程使用了同样的第三方库导致编译出错。动态库则无需注意这个问题,可以放心大胆直接用第三方库。

  • 动态库实测过可以上架的,只是iOS10之后真机不能再从沙盒加载动态库了(模拟器还是可以的),也就不存在可以热更的可能。

  • SDK工程内部如何读取bundle,取决于bundle的位置。
    1、对于静态库是固定的位置:.../***.app/***.bundle/,先获取.app路径.../***.app/mainBundlebundleForClass效果一致,再根据bundle名字获取路径下的***.bundle
    2、对于动态库,如果使用mainBundle,则是.../***.app/
    如果使用bundleForClass,是.../***.app/Frameworks/***.framework/。再根据bundle名字获取路径下的***.bundle

参考文档

NSBundle官方文档

你可能感兴趣的:(iOS SDK(二):Bundle)