一、爱奇艺

  1. iOS8 对于 App 的 text 段有 60MB 的限制;
  2. 超过 200MB 的 App 需要连接 WIFI 下载(之前是 150MB)
  3. 过大会导致启动慢,rebase/binding 时间长
  4. 除去商店中 App 的简介、截图,很多用户都会关注 App 的大小,尤其是使用空间为 8G、16G 的用户

安装包大小的优化,主要包含两大块:资源大小的优化和二进制大小的优化。

资源大小的优化相对来说比较简单,主要包括以下几个方面:

  1. 资源压缩
  2. 未使用、重复资源的删除
  3. 资源上云

1.1 资源压缩

Xcode 的编译选项中,提供了 Compress PNG FilesRemove Text MetaData From PNG Files

ios ipa包体积 ios app 体积大_App

但是由于 PNG 是无损压缩,经过 Xcode 压缩后的图片资源,依然很大。

那么 PNG 是否可以通过“有损”压缩,来缩小体积呢?答案是可以。通常 UI 同事出的图都是 32 位图片, 32 位图相当于 Alpha 透明度 + 24 位图,总共可以显示 224 = 16777216 种颜色。图片颜色丰富固然好,但是一般情况下,APP 包中的图片色彩范围实际很小,按钮或者一些小图使用 8 位图肉眼完全看不出与 32 位图有什么区别。

ios ipa包体积 ios app 体积大_开发人员_02

因此团队使用 pngquant 对大多数的 32 位图进行了处理,将其转为 8 位图,并且使用 Zopfli 进行了压缩,这样整体的 PNG 图片资源大概被压缩了 70% 左右。这里要注意,由于一些渐变背景的颜色覆盖范围较大,转为 8 位图颜色丢失较大,表现效果会差很多,所以这些图片要谨慎处理。

1.2 未使用、重复资源的删除

随着版本迭代,一些功能可能会下线,有时相关的资源却没有及时删掉,有些功能由于开发者不同,可能部分相对通用的图片会有重复。这部分资源会随着时间的推移慢慢累积,及时发现并删除是非常必要的。

图片是否被使用,可以通过图片名字符串的匹配来判断。需要注意的是图片名拼接的情况(比如新手引导的功能,很容易出现图片名拼接数字的情况),在图片资源预处理的过程中,通常有两张以上图片有相同的前缀或后缀,可以将其相同的部分提取出来,作为字符串匹配的依据。

重复资源的情况一般会发生在一些按钮、或者背景图由同一个 UI 同事生成,发给了不同功能的开发人员。这部分图片的判定一般可以通过图片大小相同或相近(大小在 5% 范围内)、分辨率相同进行初筛,然后再通过 magick compare 工具进行图片的对比,提取出相似度极大的即可。

ios ipa包体积 ios app 体积大_开发人员_03

最后工具输出的结果需要开发人员进行二次确认,确保不会有误删的情况出现。

ios ipa包体积 ios app 体积大_App_04

1.3 资源上云

资源上云可以有效减少包内资源,唯一要注意的是这些资源由于是 lazy load,所以比较适合层级较深的页面使用。图片逻辑可以封装为工具类,前端使用只是调用一个方法,具体哪些图片取本地、哪些图片走云的策略可以自由配置。此外,资源上云的另一个好处是可以很方便地实现动态换肤。

ios ipa包体积 ios app 体积大_ios ipa包体积_05

JS、表情库等资源可以通过打包预下载的形式,并增加更新策略,这样 RN 页面、WebView、表情库都不占用安装包大小。

二进制大小的优化相对来说比较困难,除去部分功能使用 Web 页面或者 RN,主要工作集中在无用类、无用代码的分析及删除。

Xcode 可以生成一个 Link Map 文件,文件包含了可执行文件的路径、目标文件、符号等各种信息。文件中 __objc_classrefs 表示引用到的类,_objc_classname 表示 App 内的类名,通过分析两者的差别,可以得出未使用的类,同理,分析 __objc_selrefs 和 _objc_methname 的差别可以得出未使用的方法。但是由于 OC 的动态性,得出的结果会有大量误报的情况。那么如何减少误报呢?可以通过测试 case 的代码覆盖率,来提高无用代码精确度的分析。

Xcode 设置中开启代码覆盖率后,编译时会生成 gcno 文件,程序运行时会产生 gcda 文件,通过 lcov 解析即可得到代码测试覆盖率。如果开发阶段开发人员的自测,以及全功能 case 跑完,都有一些类或方法没有被覆盖到,并且这些类或方法又跟 Link Map 文件分析的结果一致,那么这些类或方法会被标记为无用代码,由工具统一收集并指派给相关开发人员进行处理。

二、其他处理

  1. 配置编译选项 Generate Debug Symbols 设置为 NO;
  2. 舍弃架构,如:armv7,根据实际选择。
  3. 编译的版本必须是 release 版本,
  4. 查找内部使用到的第三方库,一方面可以进行删减代码,用不到的类,直接删除,还有第三方库中的图片资源统统删除掉,如果能够自己手写实现的,那费功夫自己写吧
  5. 图片
  • 压缩图片
    不重要的图片可适当采用 8bit png 图片

矢量图:由计算机的算法产生的,可以无限放大或缩小,不会有任何损失,通常由矢量软件制作。

位图:由一个一个的小色块组成,放大后会看到那些小色块,同一面积内小色块越多,分辨率就越高。

  • 矢量图优点:
  • 可以无限放大或缩小,不会影响图像素质;
  • 文件体积较小,编辑灵活

缺点:

  • 表达的色彩层次不清,整体观感效果不如位图

位图优点:

  • 能很细腻地表达图片的效果,图片表达效果非常好

缺点:

  • 不能放太大,减少文件分辨率后会影响图片质量
  • 图片占据空间较大

一些对图片要求高的用位图,如:照片。其他的尽量用矢量图,如:文字、表格、卡通图片等

  • 去掉无用的图片
  • 用代码绘制简单的纯色图片 用 Sketch 和 PaintCode 快速得到绘制代码。
  • 如果不需要使用透明,可以用 jpeg 代替 png。jpeg 减少了些效率但更加小。需权衡性能,大小。
  • 对 32 位的图片,尽可能的使用高压缩率,使用 PS 的“Save For Web”功能,可以有效的减小 JPEG 和 PNG 图片的尺寸。 默认情况下,在 build 时,PNG 图像就被 pngcrush 压缩。
  1. 音频
    压缩音频,尽可能使用 AAC 或者 MP3 格式,并且使用一个较低的码率。通常 44.1khz 的码率有点浪费,降低一定的码率也不会丢失多少音质。
  2. 视频
    视频也可以使用类似于音频的处理方法,音视频的压缩可以很大程度的压缩,但是要注意压缩的格式,是不是会增加编解码的负担,这要权衡考虑。
  3. Assets
    检查 bundle 中的无用文件,不要打包到 app 或者静态库中。可以点击文件,在右侧的 file inspector 里面的 target membership 中取消勾选;或者在 build phase 里面的 Copy Bundle Resources 中去掉。
    确定 dead code(代码被定义但从未被调用)被剥离,Build Settings 里 DEAD_CODE_STRIPPING = YES。去掉冗余的代码,即使一点冗余代码,编译后体积也是很可观的。