在进行组件化或者打静态库的时候,不可避免的会出现资源文件的处理,一般会有如下几种情况
- pod库中的代码读取自身pod库中的资源
- pod库中代码读取其他pod库资源
- 主工程读取pod库资源
- pod库读取主工程资源(这个读取思想是错误的)
通常如果我们在主工程调用主工程的资源时,可以直接imageName或者[mainbundle pathForResource]读取,但是在用pod进行管理的时候,pod中的资源文件也会变成bundle加入到mainBundle中,但是由于最直接的bundle并不是mainBundle,所以这种方法是行不通的,关键是要取到资源相关联的bundle
oc工程的podfile一般是不使用use_frameworks!的,swift和自己创建的lib库是默认有的,关于这两点的差异,如果不使用framework,pod里的资源文件会被打成bundle放在mainbundle下面,由于开发中每个pod库对于use_frameworks!的使用情况不一样,我们在设计工具类的时候要两者兼容 ,podspec如下
接下来我们依次看两种情况下bundle的差异
对于之中种不使用framewok的情况资源调用很简单,只需要一个bundlename参数
NSURL *associateBundleURL = [[NSBundle mainBundle] URLForResource:bundleName withExtension:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithURL:associateBundleURL];
对于使用framework的情况下的,bundle就会被分配在每个pod.framework下,这时候mainbundle的子目录就变成这样了,这个目前我还没找到好的方法(说[self class]的等下我说明下),所以目前我就是拼接的方式获取bundle路径,这里需要两个参数bundlename和podname
NSURL* associateBundleURL = [[NSBundle mainBundle] URLForResource:@"Frameworks" withExtension:nil];
associateBundleURL = [associateBundleURL URLByAppendingPathComponent:podName];
associateBundleURL = [associateBundleURL URLByAppendingPathExtension:@"framework"];
NSBundle *associateBunle = [NSBundle bundleWithURL:associateBundleURL];
associateBundleURL = [associateBunle URLForResource:bundleName withExtension:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithURL:associateBundleURL];
这就是两个模式下bundle资源的读取,两种条件下合并之后就变成这样:
@implementation NSBundle (AssociatedBundle)
/**
获取文件所在name,默认情况下podName和bundlename相同,传一个即可
@param bundleName bundle名字,就是在resource_bundles里面的名字
@param podName pod的名字
@return bundle
*/
+ (NSBundle *)bundleWithBundleName:(NSString *)bundleName podName:(NSString *)podName{
if (bundleName == nil && podName == nil) {
@throw @"bundleName和podName不能同时为空";
}else if (bundleName == nil ) {
bundleName = podName;
}else if (podName == nil) {
podName = bundleName;
}
if ([bundleName containsString:@".bundle"]) {
bundleName = [bundleName componentsSeparatedByString:@".bundle"].firstObject;
}
//没使用framwork的情况下
NSURL *associateBundleURL = [[NSBundle mainBundle] URLForResource:bundleName withExtension:@"bundle"];
//使用framework形式
if (!associateBundleURL) {
associateBundleURL = [[NSBundle mainBundle] URLForResource:@"Frameworks" withExtension:nil];
associateBundleURL = [associateBundleURL URLByAppendingPathComponent:podName];
associateBundleURL = [associateBundleURL URLByAppendingPathExtension:@"framework"];
NSBundle *associateBunle = [NSBundle bundleWithURL:associateBundleURL];
associateBundleURL = [associateBunle URLForResource:bundleName withExtension:@"bundle"];
}
NSAssert(associateBundleURL, @"取不到关联bundle");
//生产环境直接返回空
return associateBundleURL?[NSBundle bundleWithURL:associateBundleURL]:nil;
}
@end
以上就是读取pod中bundle的方式,bundle拿到之后,资源文件就可以各种方式拿了。
关于其他文章说的【self class】取bundle的理解
先贴出其他文章的代码
NSBundle *bundle = [NSBundle bundleForClass:[MYSomeClass class]];
NSURL *bundleURL = [bundle URLForResource:bundleNamewithExtension:@"bundle"];
NSBundle *resourceBundle = [NSBundle bundleWithURL: bundleURL];
接下来说说我对这里,个人觉得像这种取bundle资源的方法是应该放在一个公用的方法库里(pod库),而且用分类的方式实现会更好理解一点,这里关于【self class】就涉及到两个问题,
- 在分类里面【self class】取bundle是取不到的
- 公共资源会单独形成一个pod,这时候如果其他pod调用这个资源pod,就没有class这一说
由于这两个问题,所以我目前采用的是上面那种自己拼接url的方案