针对目前公司业务子库资源引用方式各异,包体大小超出正常值的问题,做出了一些调研.同时网上的部分说法可能随着时间的推移和cocoapods的更新已通过时或不可用.本文展现了资源引用的各类方式,也防止你们走弯路.css
这篇文章介绍了关于CocoaPods的资源管理行为,对于Pod库做者是必须了解的知识。同时介绍了CocoaPods使用Asset Catalog的注意事项。若是已经了解某方面知识,能够大体略过直接看结论。html
Asset Catalog,是Xcode提供的一项图片资源管理方式。每一个Asset表示一个图片资源,可是能够对应一个或者多个实际PNG图,好比能够提供@1x
, @2x
, @3x
多张尺寸的图以适配;,还能够经过指定日间和夜间不一样Appearances的两套图片。json
这种资源,在编译时会被压缩,而后在App运行时,能够经过API动态根据设备scale factor来选择对应的真实的图片渲染。xcode
App Thinning,是苹果平台(iOS/tvOS/watchOS)上的一个用于优化App包下载资源大小的方案。在App包提交上传到App Store后,苹果后台服务器,会对不一样的设备,根据设备的scale factor,从新把App包进行精简,这样不一样设备从App Store下载须要的容量不一样,3x设备不须要同时下载1x和2x的图。ruby
可是,这套机制直接基于Asset Catalog,换言之,只有在Asset Catalog中引入的图片,才能够利用这套App Thinning。直接拷贝到App Bundle中的散落图片,全部设备仍是都会所有下载。所以如何尽可能提高Asset Catalog利用率,是一个很大的包大小优化点。服务器
CocoaPods是一个构建工具,它彻底基于Pods的spec文件规则,在Podfile引入后,生成对应构建Xcode Target。也就是它是一个声明式构建工具(区别于Makefile这种过程式的构建工具)。对于资源的管理,目前有两个方式进行声明并引入,即resources
和resource_bundles
,参考podspec syntaxapp
虽然Podspec中包含全部待构建库的声明,但于CocoaPods也会根据Podfile的配置,动态调整最终的Xcode工程的配置,根据是否开启use_framework!
,如下的资源声明最终的行为有所不一样,这里分开介绍。ide
为了测试使用场景,咱们新建了三个工程 工程目录以下:工具
主工程为 CatalogTest ,测试
资源工程为: ResourcesTest,ResourcesBubdlesTest
ResourcesTest 里包含资源文件:
ResourcesBubdlesTest包含资源文件:
/Assets/**/*'
s.resources = 'ResourcesTest/Assets/**/*'
导入方式
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/**/*']
}
复制代码
而经过resources 导入的文件直接会在根目录导入两份而且不会 通过Xcode的资源优化
bundle也会以bundle和里面的全部文件在根目录导入
经过resource_bundles 形式导入的文件会生成一个自命名的 budle ,bundle里包含文件
结论: 按照**/*
导入的资源文件不管哪一种形式都存在被重复导入的问题,这种懒省事的方式应该被制止
/Assets/*.xcasset'
,/Assets/*.bundle
ResourcesTest:
xcasseets并入主工程 .car
Bundle 并入主目录
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
复制代码
ResourcesBubdlesTest:
注意 bundle必须有本身的命名空间,不然仍是以文件形式导入
Bundle 文件会以命名空间为名字放在主目录下
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
复制代码
为了测试使用场景,咱们新建了三个工程 工程目录以下:
主工程为 CatalogTest ,
资源工程为: ResourcesTest,ResourcesBubdlesTest
ResourcesTest 里包含资源文件:
ResourcesBubdlesTest包含资源文件:
/Assets/**/*'
导入方式 s.resources = 'ResourcesTest/Assets/**/*'
xcassets 生成.car, bundle文件依然双份
导入方式
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/**/*']
}
复制代码
/Assets/*.xcasset'
,/Assets/*.bundle
每一个子工程有本身的 framework,也就是有本身的命名空间,不会出现命名冲突等问题
ResourcesTest:
xcasseets并入主工程 .car
Bundle 并入主目录
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
复制代码
ResourcesBubdlesTest:
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
复制代码
不管任何场景,禁止 使用 podspecName/assers/**/*
形式引入资源文件,存在严重的资源重复引入问题,会显著增长包体大小!没法享有任何 Xcode的优化.
resources
s.resources = ['ResourcesTest/Assets/*.xcassets',
'ResourcesTest/Assets/*.bundle'
]
复制代码
使用 resource_bundles
s.resource_bundles = {
'ResourcesBubdlesTest' => ['ResourcesBubdlesTest/Assets/*.xcassets'],
'BlankLoading1' => ['ResourcesBubdlesTest/Assets/BlankLoading.bundle']
}
复制代码
当不使用use_framework!时,最终对Pod库,会建立单独的静态连接库.a
的Target,而后CocoaPods会对主工程App Target增长本身写的脚原本帮助咱们拷贝Pod的资源。
resources
里*.xcassets
资源会拷贝进入主目录Assets.car
,*.bundle
文件放入主目录下!
优势:
最简单暴力,并且因为固定了资源的路径在根路径上,若是先前在主工程目录中使用的代码,不须要更改一行便可继续使用。
缺点:
bundle
, js
, css
均可能存在这个问题,难以排查。并且因为这种拷贝到根路径的机制,这个问题不可从根源避免。resource_bundles
文件*.xcassets
会放入 命名空间.bundle
下的Assets.car
,*.bundle
放入主目录下的命名空间.bundle
优势:
解决了部分命名冲突问题,*.xcassets
存在本身的命名空间.
缺点:
当使用了use_framework!以后,CocoaPods会对每一个Pod单独创建一个动态连接库的Target,每一个Pod最后会直接以Framework集成到App中。而资源方面,因为Framework自己就能承载资源,全部的资源都会被拷贝到Framework文件夹中而再也不使用单独的脚本处理。
优势:
不会存在命名冲突。由于在使用use_framework!的状况下,因为资源自己被拷贝到Framework中,已经能最大程度减小冲突,所以这时候通常不须要考虑名称冲突问题.
都会使用Xcode的优化
缺点: 因为最终的资源文件增减了一级父文件夹.因此资源引用方式要作出改变
结合咱们公司目前现状不能使用动态库.因此使用以下方案:
业务层使用resources
导入资源
资源文件使用 *.xcassets
*.bundle
*.text
方式导入,可是各子库文件会存在命名冲突问题,好处是不用改变资源引用方式,
同时约定,各子库的资源添加子库名字缩写的前缀,避免暴力拷贝问题
基础服务层,和工具层使用resource_bundles
.plist
.json
.html
须要建一个bundleName.bunlde
,不然没法导入!