组件化图片资源管理

背景

目前项目App包体积较大,分析项目中图片资源占据比例较大,首先从图片方面进行优化。

1.图片集成方式

现状:目前pod库中图片直接存放在bundle下,存在@2x,@3x图,通过bundle去访问图片资源。

这样会造成安装的设备中同时存在@2x和@3x的图片。

如果使用Asset Catlogs去管理图片,即下图使用.xcasset的形式,xcassets 里面的 @2x、@3x 会根据具体设备分发,只包含符合目标设备分辨率的图片,不会同时包含,以此来缩小用户下载的包体积。(App Slicing)

以下为实验结果:

结论:使用Asset catalogs取代Bundle管理图片的形式

2.图片资源引用方式

使用Asset catalogs管理图片资源来取代Bundle管理图片的形式,包体积会减少,那么我们在使用时也需要注意以下问题

2.1 图片资源冲突

经过打包测试,在静态库中Asset catalogs管理的图片资源是与主工程Asset catalogs管理的图片资源统一生成为一个Asset.car的文件,所以其中有可能存在图片冲突的问题。

如果两个图片名称一致,但是图片是不一样的内容,那么就会存在加载错图片的问题。所以在静态库中使用Asset catalogs要格外注意。

2.2 图片管理方式分析

那么pod库中,我们改通过何种方式去管理图片资源,有各有什么优缺点,以下进行了整理

图片管理方式 引用方式 分析 使用建议
静态库 Bundle resources 同时存在@2x和@3x的图片
静态库 Bundle resource_bundle 同时存在@2x和@3x的图片
静态库 Asset catalogs resources 仅包含一种分辨率图片,但有可能与主工程图片资源冲突
静态库 Asset catalogs resource_bundle 仅包含一种分辨率图片,且不会有冲突 ✔️
动态库 Bundle resources 同时存在@2x和@3x的图片
动态库 Bundle resource_bundle 会造成bundle中嵌套bundle
动态库 Asset catalogs resources 仅包含一种分辨率图片 ✔️
动态库 Asset catalogs resource_bundle 仅包含一种分辨率图片,由于动态库本身图片资源是在自身framework中,不存在与其他pod库资源冲突的问题 ✔️

关于resources 与 resource_bundle的区别在于:

resource_bundles 允许定义当前 Pod 库的资源包的名称和文件。用 hash 的形式来声明,key 是 bundle 的名称,value 是需要包括的文件的通配 patterns。

CocoaPods 官方强烈推荐使用 resource_bundles,因为用 key-value 可以避免相同名称资源的名称冲突。

使用 resources 来指定资源,被指定的资源只会简单的被 copy 到目标工程中(主工程),所以存在资源冲突的问题。

2.3 如何调用

使用resource_bundle调用图片的方式与使用resources的有所不同:

1
2
3
4
5
6
7
let currentBundle = Bundle.init(for: ShowBundleIconController.self)
let bundle = Bundle(url: currentBundle.url(forResource: "IconBundleModule", withExtension: "bundle")!)
let image = UIImage(named: "es8_pearlwhite_side", in: bundle, compatibleWith: nil)

let imageView = UIImageView(frame: CGRect(x: 0, y: 100, width: 200, height: 100))
imageView.image = image
view.addSubview(imageView)
3.IconFont

针对于单色的图标,我们也可以用IconFont来管理:

1.以tff的形式来管理图片,减少体积

2.以阿里IconFont为例,生成tff文件所上传的svg限制单个大小为40KB

3.在iOS项目中不支持多色的使用

4.使用方式

以下为几种使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

// ----------------------------- 未封装前用法 使用UILabel去展示 --------------------------------------------
let label = UILabel(frame: CGRect(x: 30, y: 100, width: 50, height: 50))
label.font = UIFont.init(name: "iconfont", size: 50)
label.text = "\u{e604}"
view.addSubview(label)

// ----------------------------- EFIConFont 使用UILabel去展示 --------------------------------------------
let iconlabel = UILabel(frame: CGRect(x: 30, y: 170, width: 50, height: 50))
iconlabel.font = EFIconFont.antDesign.cake.font(size: 50)
iconlabel.text = EFIconFont.antDesign.cake.unicode
iconlabel.textAlignment = .right
view.addSubview(iconlabel)

// ----------------------------- EFIConFont 使用UIImageView去展示 --------------------------------------------
let iconImgView = UIImageView(frame: CGRect(x: 30, y: 240, width: 50, height: 50))
iconImgView.image = EFIconFont.antDesign.dessert.image(size: iconImgView.frame.size)
view.addSubview(iconImgView)

// ----------------------------- EFIConFont 使用UIImageView去展示 --------------------------------------------
let iconImgView1 = UIImageView(frame: CGRect(x: 100, y: 240, width: 50, height: 50))
iconImgView1.image = EFIconFont.antDesign.dessert.image(size: iconImgView1.frame.size, foregroundColor: UIColor.red)
view.addSubview(iconImgView1)

// ----------------------------- EFIConFont 使用富文本去展示 --------------------------------------------
let iconAttributeLbl = UILabel(frame: CGRect(x: 30, y: 300, width: 50, height: 50))
iconAttributeLbl.attributedText = EFIconFont.antDesign.dessert.attributedString(size: 50)
iconAttributeLbl.textAlignment = .right
view.addSubview(iconAttributeLbl)
总结

1.采用Assets catalogs来代替 Bundle管理的资源

2.对于单色的简单图标,可以采用IconFont,但减少体积有限,且替换成本较高。