iOS 包体积优化4 - 资源管理

8,087 阅读9分钟

iOS包体积优化的系列文章,其中包括:

根据分析ipa包结果,可知道资源文件类型:

  • 图片资源文件
  • json资源文件
  • zip资源文件
  • plist资源文件

对于资源文件的处理方式:

  • 能删除的就删除
  • 能压缩的就压缩
  • 能替换的就替换
  • 能复用的就复用

大部分app资源主要是图片,图片一般以三种形式存在于 安装包中:

  • 在主项目中使用Images.xcassets管理的图片,会平铺压缩到 Assets.car 文件中。
  • 在主项目中直接放工程路径中的图片,会存在于ipa的一级目录中。
  • 还有一些存在于bundle中图片。

一. 清理废弃图片

1. LSUnusedResources

1.1 简介

用于查找 Xcode 项目中未使用的图像和资源的 Mac App。

这个app的原理是,对某一文件目录下所有的源代码文件进行扫描,用正则表达式匹配出所有的@"xxx"字符串(会根据不同类型的源代码文件使用不同的匹配规则),形成“使用到的图片的集合”,然后扫描所有的图片文件名,查看哪些图片文件名不在“使用到的图片的集合”中,然后将这些图片文件呈现在结果中。

LSUnusedResourcesExample.gif

  • Project Path: 项目路径
  • Exclude Folder: 排除的文件夹, 如果有多个用 “|” 隔开。例如: EmptyView|MainImage
  • Resource Suffix: 要查找的资源后缀,用“|” 隔开。
  • Ignore similar name: 过滤掉类似命名的资源。例如:“tag_1.png”,“tag_2.png”
  • Name (click to Copy) : 点击可以复制名称。
  • Size(KB) :文件大小,点击可以排序。

1.2 地址

地址: github.com/tinymind/LS…

1.3 使用

  1. 点击 Browse.. 选择工程文件目录。
  2. 点按 Search 以开始搜索。
  3. 等待几秒钟,结果将显示在表视图中。

1.4 注意

  • 查找完一定要人工确认无误之后再删除。
  • 建议按批次处理,确认一部分,删一部分,提交一次。

2. WHC_ScanUnreferenceImageTool

2.1 简介

用于查找 Xcode 项目中未使用的图像和资源的 Mac App

  • 高效 : Mac扫描项目图片工具(扫描项目里没有使用的资源图片)
  • 好处 : 删除没有使用的资源图片以减小打包体积
  • 强大 : 支持iOS 和 Android项目

WHC_ScanUnreferenceImageTool.gif

2.2 地址

地址: github.com/netyouli/WH…

2.3 使用

  • 运行项目
  • 通过 打开目录 按钮,打开项目目录(根目录即可)。
  • 点击 开始扫描 按钮,等待一段时间即可出结果。

2.4 注意

  • 查找完一定要人工确认无误之后再删除。
  • 注意拼接图片名的情况,防止误删。
  • 最好采用 double check 的方式,双人验证。

二. 大图片的查找

大图的处理,主要难在查找比较麻烦,通过以下4种途径,相信可以找到要处理的大图片范围了。

如何定义大图片? 一般认为单张图片大于200KB,就算大图片了。 需要根据具体情况进行分析,例如: 如果这个图片是一个背景图(可以接受拉伸,适当模糊)这个临界点就可以小一点。

1. 直接通过Images.xcassets查找大图片

直接 show in finder打开 Images.scassets 文件,将文件夹展开到最后一层(后缀为 .imageset)。将大的图片集文件名记录下来。

查找大图片.png

2. 通过分析car文件查找大图片

我们将ipa包解压之后获得的 Assets.car 文件,是没办法针对图片大小排序的。 可以通过工具 AssetCatalogTinkerer 达到根据文件大小排序的目的。

  1. 下载并安装 AssetCatalogTinkerer

地址: github.com/insidegui/A…

  1. 打开项目,此时不会有程序框出来, 菜单栏中 -> File -> Open -> 选择 .car文件

Asset Catalog Tinkerer open.png

  1. 选择导出文件, 菜单栏 -> File -> Export All Images -> 导出到指定的文件夹内

Asset Catalog Tinkerer export.png

对导出的图片排序分析(使用Finder提供的根据大小排序功能)(导出来的图片会自动包含_Normal, 搜索的时候自行去掉)

Asset Catalog Tinkerer sort.png

  • 如何将导出的图片对应到 项目中的Assets.car 文件 中?

拿到图片的名称,在工程目录下,搜索图片,可以看到图片的路径,就可以知道 图片对应的 .imageset 的名称。

3. 查看ipa的一级目录中的图片

在ipa的一级目录中,筛选出大图片。

4. 查看存在bundle中的图片。

查看bundle的包内容,通过查看car文件,筛选出大图片。

三. 对大图片进行的处理

压缩处理

我们的图片类型一般是 pngjpg 格式的。一般jpg图片是以文件的形式存在于工程目录中的,png图片一般是存在在imageset中的。

作者对找出来的大图片进行无损压缩,可以使用的压缩工具: tinypng

图片压缩之后的图片变小了很多,开心的打包验证之后发现 .car文件 没有明显的变化。仔细对比里面的图片大小之后,发现图片大小又回到压缩之前了。

通过实验发现,不同的情况,压缩效果不一样:

情况效果
存在于imageset中的png图片压缩无效,甚至有可能是负优化
存在于工程目录中的png图片没有验证(不应该有存在于工程目录的png图片)
存在于工程目录中的jpg图片压缩有效

PNG图片压缩无效的原因

查了一些资料发现一些端倪:

Xcode 的 Build Setting 设置里面有一个 Compress PNG Files 的选项, 如果选择了 YES, 那么 Xcode 在编译阶段将会对所有 png 图片进行压缩。

如果对放入 Images.xcassets 中的png进行无损压缩。实践后发现,虽然放入 Asset Catalog 的图片大小有了明显减小,但是构建的产物的大小却几乎没有变化。原因是Xcode 中,构建 Asset Catalog 的工具 actool 会首先对 Asset Catalog 中的 png 图片进行解码,得到 Bitmap 数据,然后再运用 actool 的编码压缩算法进行编码压缩处理。无损压缩通过变换图片的编码压缩算法减少大小,但是不会改变 Bitmap 数据。对于 actool 来说,它接收的输入没有改变,所以无损压缩无法优化 Assets.car 的大小。甚至会有反向增大的情况。

苹果自带了对PNG图片的压缩方式,所以如果图片格式是PNG的话,将图片Images.xcassets 中管理,可以享受到苹果的压缩优化。

使用 70% 的有损压缩是一个不错的方式,既能保证图片清晰度的同时获得更小的大小。如果对于有半透明效果的图片,采用 70% 的有损压缩会导致半透明的地方出现噪点,所以压缩过后的图片最好找设计师同学再确认一次。

推荐使用 ImageOptim 进行 有损压缩。

image.png

大图片的其他处理方式

1. 转换格式

对于较大的PNG图片(Compress PNG Files 导致压缩无效),可以转为JPG格式图片,存放在工程路径中(不存放在 Images.scassets中),JPG图片本身比PNG图片小很多,差不多要小90%。

2. 考虑使用WebP格式图片

建议实践中比如页面背景图,或者其他 png 格式超过 100KB 大小的图片都使用 WebP 的方式引入。相较于 PNG 格式,WebP 具有更加优秀的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量。 或像素要求不高的图片

3. 云端下载策略

在若干时机尝试下载zip图片包,对zip包进行版本判断,若云端有更新版本,则根据屏幕是3x还是2x,下载对应的zip包,解压存入沙盒中;

在读取图片时,首先从bundle中读取,若失败,则从沙盒中读取,若依然失败,则将该图片当作一个网络图片进行请求,确保图片能被展示。

四. 相同类型图片的处理

1. Tink Color

适合多个图标的形状是完全一致的,只是颜色有差异(只有一种颜色)的图片类型。

tint color是苹果在iOS7推出的功能,我们可以读取一个图标,然后给它赋予一个color值,在手机屏幕上它就能显示出相应的效果。tint color适用于对单色图标进行着色,相比于其他精简图标的解决方案,tint color方便、可靠、拥有原生支持。

五. 图片管理方式

1. 主工程中

尽量将PNG图片资源放入 Images.xcassets 中,包括 pod 库的图片。 Images.xcassets 中的图片加载后会有缓存,提升加载速度,并且在最终打包时会自动进行压缩(Compress PNG Files),再根据最终运行设备进行 2x 和 3x 分发。可以直接享受苹果对PNG的压缩服务。

建议使用频率高且小的图片放到 Asset.car 中,Asset.car 能保证其加载和渲染的速度最优。而大的图片比如背景图之类的,长宽尺寸就有上千个像素,而这种放到 Asset.car 中会大大的增加安装包的大小。

2. 组件库中

由于项目采用组件化开发,较多组件的资源图片是放到目录里面,通过bundle的形式导入工程中的,没有使用Images.xcassets 管理,针对这一块图片的压缩还是有价值的。

对于内部 Pod 库中的资源文件,我们可以在 Pod 库里面的 Resources 目录下新建 Asset Catalog 文件,命名为 Images.xcassets,移入所有图片文件,接着手动修改该 组件库 的 podspec 文件指定使用该 Images.xcassets。

  s.ios.resource_bundle = { 'BTUIBundle' => '路径' }

Pod 资源文件的引用方式分为 resource_bundlesresources,这里我们使用的是 resource_bundles,会为为指定的资源打一个 .bundle.bundle包含一个 Assets.car,获取图片的时候要严格指定 bundle 的位置,能很好的隔离各个库资源包。