Pod库图片资源管理

CocoaPods中管理图片资源

CocoaPods在.podspec文件中描述资源的字段有两个,resources和resouce_bundles。

resources

使用方式如下:

spec.resource = 'Resources/HockeySDK.bundle'
spec.resources = ['Images/*.png', 'Sounds/*']

CocoaPods不推荐使用resources,因为它会产生图片资源冲突。

使用"*.png"描述资源

此时打包之后Pod库图片会出现在安装包里,没有进入主工程的Assets.car中,不同Pod库中相同名字的图片会在安装包里冲突导致被覆盖掉。

使用"*.bundle"描述资源

此时打包之后Pod库的bundle文件会出现在安装包里,不同Pod库的同名bundle文件会融合成一个bundle文件,而bundle文件中相同名字的图片就会冲突然后被覆盖掉。

使用"*.xcassets"描述资源

此时Pod库的.xcassets中的图片会被打包到主工程的Assets.car中,不同Pod库中相同名字的图片会在Assets.car中出现冲突然后被覆盖。

上面详细描述了使用“resources”来描述图片资源时,打包之后图片所在的位置,及造成图片冲突的原因。

resource_bundles

使用方式如下:

spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
spec.resource_bundles = {
    'MapBox' => ['MapView/Map/Resources/*.png'],
    'MapBoxOtherResources' => ['MapView/Map/OtherResources/*.png']
}

resource_bundles内部通过一对key-value来描述资源,对每一个key生成一个bundle,value则是该bundle下的图片资源;为了减少key冲突,CocoaPods建议key至少包含Pod的名字,同一个Pod库下不同的bundle在Pod的名字之后加上不同的后缀。

CocoaPods推荐使用resource_bundles来管理图片资源,但是有一个非常严重的问题需要注意:https://github.com/CocoaPods/CocoaPods/issues/8431,就是当项目中有一个Pod库采用了resources&xcasset的方式描述资源时,项目所有Pod库中的xcasset都会被拷贝到主工程的Assets.car中;此时如果有一个Pod库使用了resource_bundles&xcasset描述资源时,该Pod的xcasset中的图片也会被拷贝到主工程的Assets.car中,这会与Pod库的自己bundle中生成的Assets.car图片造成重复,产生这个问题的地方在于执行pod install之后生成的Pods-xxxxx-resource.sh脚本里的如下代码中:

if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
then
  # Find all other xcassets (this unfortunately includes those of path pods and other targets).
  OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
  while read line; do
    if [[ $line != "${PODS_ROOT}*" ]]; then
      XCASSET_FILES+=("$line")
    fi
  done <<<"$OTHER_XCASSETS"

  if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
    printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
  else
    printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
  fi
fi

上述issue中提供了可以复现的demo,而且CocoaPods的作者按时安排在1.9版本中解决这个问题。

CocoaPods中图片资源的使用

NSBundle

再来熟悉一下文档中对Bundle的描述,"Apple uses bundles to represent apps, frameworks, plug-ins, and many other specific types of content",也就是说项目打包好的.app和frameworks都是一个Bundle。

查找并且打开一个NSBundle的创建方式大致分如下两种:

  • +[NSBundle mainBundle]
    "The main bundle represents the bundle directory that contains the current executing code. So for an app, the main bundle object gives you access to the resources that shipped with your app." 可以理解为.app就是一个Bundle。
// Get the app's main bundle
NSBundle *main = [NSBundle mainBundle];
  • +[NSBundle bundleForClass:]
    "if you link to a framework, you can use the bundleForClass: method to locate the framework bundle based on a class defined in that framework." 当我们想要获取一个Framework的Bundle时,就可以通过这个方法,方法参数是这个framework中定义的一个类。需要注意的是如果当前framework是静态库时,该方法等同于[NSBundle mainBundle]。
// Get the bundle containing the specified private class.
NSBundle *myBundle = [NSBundle bundleForClass:[MyPrivateClass class]];

获取当前Pod的图片资源

按照CocoaPods的建议,使用resource_bundles来描述资源文件,为了避免其他Pod库使用resources&xcasset给我们的Pod库造成麻烦,我们的Pod内部使用*.png来管理图片资源。

s.resource_bundles = {
  'XCCategory' => ['XCCategory/Assets/*.png']
}

我们目前Pod库是静态库,所以会在.app下生成一个"XCCategory.bundle"。

当前Pod可能作为动态库或者静态库,为了兼容这两种情况,使用bundleForClass:来获取Pod的bundle,当Pod作为静态库时,该方法返回的是mainBundle,当Pod作为动态库时,该方法返回的就是动态库本身。

下面代码获取到了XCCategory.bundle,然后从XCCategory.bundle中取出对应的图片。

+ (nullable UIImage *)xccategory_imageName:(NSString *)name {
    static NSBundle *resourceBundle = nil;
    if (resourceBundle == nil) {
        resourceBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[XCCategoryViewController class]] pathForResource:@"XCCategory" ofType:@"bundle"]];
    }
    
    UIImage *image = [UIImage imageNamed:name inBundle:resourceBundle compatibleWithTraitCollection:nil];
    return image;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容