[CocoaPods]podspec文件中的resource和resource_bundle

相信基本上所有的iOS开发同学针对于CocoaPods都不陌生。即便没有用过,也是久闻大名如雷贯耳。作为Objective-C和Swift中非常流行的依赖管理工具,它拥有超过10000个公有程序库,通过一份Podfile文件和pod install命令就能帮助开发者方便的管理工程依赖。

随着组件化越来越火热,大家都开始介入研究。组件化就免不了通过CocoaPods创建自己的私有代码库。而针对于一些业务模块,不光有代码,还有一些其他的资源,如图片、音视频等等。那么,下面就介绍一下如何给Pod库添加资源文件。

在CocoaPods中,官方提供了两汇总资源文件的引用方式——resourceresource_bundles

添加资源文件的字段

resources

官方解释:一系列待复制到目标工程中的资源文件。

使用方法:

指定一个bundle为资源文件
spec.resource = 'Resources/HockeySDK.bundle'
指定多个目录下的不同文件为资源文件
spec.resources = ['Images/*.png', 'Sounds/*']

(注意一个和多个的区别,多个在属性resource后面加s)

官方提示:如果构建静态库Pod时,强烈推荐使用resource_bundles来指定资源包,因为可以避免名称冲突。

resource_bundles

官方解释:允许定义当前Pod库的资源包的名称和文件。使用了hash,其中key表示包的名称,value是对应应包含的文件。key的命名至少应该包含Pod的名称,以最大限度的减少命名冲突的可能性。

使用方法:

指定一个目录下的所有png图片为一个资源包
spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
指定多个资源包
spec.resource_bundles = {
    'MapBox' => ['MapView/Map/Resources/*.png'],
    'OtherResources' => ['MapView/Map/OtherResources/*.png']
  }

(注意一个和多个的区别,多个在属性resource_bundle后面加s)

接下来我们来测试一下,为什么resource会容易产生命名冲突。

通过resources、resource_bundles直接管理资源文件

创建一个私有pod,里面分别resource和resource_bundles字段。

Pod::Spec.new do |s|
  s.name         = "TestResource"
  s.version      = "0.0.1"
  s.summary      = "TestResource"
  s.homepage     = "http://www.sogou.com"
  s.author       = { "kingsword" => "[email protected]" }
  s.platform     = :ios, "8.0"
  s.ios.deployment_target = "8.0"
  s.source       = { :svn => "http://[email protected]/svn/browser/seqa/qadev/src/iOS/ComponentLibraries/ComponentProjects/TestResource", :tag => "#{s.version}" }

  s.resource = ['resource/*.png']

  s.resource_bundle = { 'ResourceBundleA' => ['resource_bundle/*.png'] }

end

而这两个目录结构是这样的

[CocoaPods]podspec文件中的resource和resource_bundle_第1张图片

之后,我们在另外一个工程中集成这个pod并构建,构建完成后查看.app文件目录。

[CocoaPods]podspec文件中的resource和resource_bundle_第2张图片

我们发现,通过resources属性集成的资源文件都直接拷贝到了.app的根目录,而通过resource_bundle属性集成的资源文件,都被放到了ResourceBundleA.bundle目录中,并且这个bundle目录被拷贝到了.app的根目录。

此时,我们再在主工程中增加两个不同的图片,但图片的命名分别是[email protected][email protected]

[CocoaPods]podspec文件中的resource和resource_bundle_第3张图片

此时,我们再次构建,再查看目录。

[CocoaPods]podspec文件中的resource和resource_bundle_第4张图片

我想结果大家可能也猜到了。因为主工程的同名文件也会被拷贝到.app目录中,所以会覆盖我们之前集成pod中的同名文件,产生冲突。而针对于ResourceBundleA.bundle中的资源文件,因为不属于同一目录结构,所以不会被覆盖。但是之前我们讲resource_bundles时针对于key(bundle的命名)官方也建议我们能包含pod名,来尽可能的避免冲突。

通过resources、resource_bundles来管理xcassets

上面说的直接集成图片资源文件,其实在项目中用的比较少了,大部分我们都是通过xcassets来集成图片资源文件,那么这两种方式针对集成xcassets有什么不一样的呢?接下来我们还是看一下例子。

Pod::Spec.new do |s|
  s.name         = "TestResource"
  s.version      = "0.0.1"
  s.summary      = "TestResource"
  s.homepage     = "http://www.sogou.com"
  s.author       = { "kingsword" => "[email protected]" }
  s.platform     = :ios, "8.0"
  s.ios.deployment_target = "8.0"
  s.source       = { :svn => "http://[email protected]/svn/browser/seqa/qadev/src/iOS/ComponentLibraries/ComponentProjects/TestResource", :tag => "#{s.version}" }

  s.resource = ['resource.xcassets']

  s.resource_bundle = { 'ResourceBundleA' => ['resource_bundle.xcassets'] }

end
[CocoaPods]podspec文件中的resource和resource_bundle_第5张图片

我们重复集成到新工程中,构建并查看.app目录。

[CocoaPods]podspec文件中的resource和resource_bundle_第6张图片

然后我们通过Asset Catalog Tinkerer分别打开根目录下的Assets.car和ResourceBundleA.bundle目录下的Assets.car。

[CocoaPods]podspec文件中的resource和resource_bundle_第7张图片 [CocoaPods]podspec文件中的resource和resource_bundle_第8张图片

我们发现,通过resource集成的xcassets被放到.app根目录下的Assets.car包中,而通过resource_bundle集成的xcassets被放到了ResourceBundleA.bundle目录下的Asset.car包中。

这事我们继续在主工程的Asset.xcassets中新建同名的图片资源,然后继续打包,查看根目录下的Assets.car文件。

[CocoaPods]podspec文件中的resource和resource_bundle_第9张图片 [CocoaPods]podspec文件中的resource和resource_bundle_第10张图片

答案很明显,再次被覆盖了。所以如果为了尽可能的避免冲突、被覆盖,++那么还是老老实实的使用resource_bundles属性吧++。

bundle中的asset.car里面的图片如何正确加载?

其实我们总使用[UIImage imageNamed:]方法,但是其还有重载方法,可以指定bundle的[UIImage imageNamed: inBundle: compatibleWithTraitCollection:]

已上面的例子,用法如下:

//拼接bundle
NSString * bundleNameWithExtension = @"ResourceBundleA.bundle";
NSString * bundlePath = [[NSBundle bundleForClass:[MyViewController class]].resourcePath
                             stringByAppendingPathComponent:bundleNameWithExtension];
NSBundle * bundle = [NSBundle bundleWithPath:bundlePath];
UIImage * image = [UIImage imageNamed:@"icon_sina" inBundle:bundle compatibleWithTraitCollection:nil];

这样写代码,就必须要记住bundle的名称,有一些硬编码在,但是为了解决不必要的冲突,也是可以接受的,可以定义一些宏来减少硬编码的问题。

总结

其实无论要实现什么样的功能,两个属性都可以实现,只不过在最终编码上可能有一些差别。

当然在通过resource集成资源文件时,也可以先将资源文件放入bundle中,然后resource对应该bundle目录,这样使用效果其实与resource_bundle就一致了,只不过会有一些额外操作而已。

如果在多人开发环境中要去管理资源文件,还是建议使用resource_bundles并且建立一套命名规范,来减少资源冲突导致的覆盖,避免不必要的麻烦。

你可能感兴趣的:(iOS开发)