原文地址
随着业务的不断迭代,APP安装包会越来越大。包过大既影响用户体验、影响升级率、导致无法提交App Store和非WiFi环境下无法下载的问题。怎样对App进行瘦身成了重中之重。
App Thinning是由苹果公司推出的一项可以改善App下载进程的技术,它只适用于iOS9及以上系统。主要解决了用户下载App耗费过高流量问题,同时还可以节省用户iOS设备的存储空间。
现在,市面上的iOS设备多种多样,如果想在多种屏幕上都能视觉效果良好,就需要大量的优化资源来匹配不同分辨率的屏幕。同时,APP还包含针对arm64、arm7s、arm7等多种架构的优化,3D图形技术(OpenGL, Metal等),还有音频以及其他不同的文件。如果这些资源都在一个包里,势必会使用户的安装包变大。
App Thinning 会自动检测用户的设备类型,并且只下载当前设备所适用的内容。。如:iPhone 6只会下载 2x分辨率的图片资源,iPhone 6plus则只会下载3x分辨率的图片资源。用户仅需下载自己当前使用的特定设备所需的内容,这不仅加快了下载速度,还节约了设备的存储空间。
App Thinning类型
App Thinning由三个方面构成:App Slicing、On Demand Resources以及Bitcode。
App Slicing
向iTunes Connect上传App后,会对App进行切割,创建不同的变体,一个变体只包含针对某个目标设备的可执行架构与资源等,这样就可以适应到不同的设备。
On Demand Resources
按需加载资源是在app第一次安装后可下载的文件。举例说明,当玩家解锁游戏的特定关卡后可以下载新关卡相关的内容。此外,玩家已经通过的关卡可以被移除以便节约设备上的存储空间。
通过设置Xcode中的Build Settings设置,可以开启按需加载。
Bitcode
Bitcode有些抽象,但在本质上它也是苹果在用户下载前优化app的新方式。Bitcode使得app无论在何设备上都能快速高效地运行。Bitcode使用最新的编译器自动编译app并且针对特定架构进行优化(ps:优化效果并不明显)。
Bitcode不会下载应用针对不同架构的优化,而仅下载与特定设备相关的优化,使得下载量更小。
可以通过Build Settings下的选项进行设置,将bitcode设为YES来完成。
如何使用App Thinning?
虽然Xcode和App Store帮你完成了App Thinning的主要流程,但是你需要确保你的app支持这项新技术。首先,你必须启用资产目录。

按照Asset Catalog的模板添加图片资源即可,添加的2x分辨率的图片和3x分辨率的图片,会在上传到 App Store后被创建成不同的变体以减小App安装包的大小。架构文件只需要按照默认的设置, App Store就会根据设备创建不同的变体,每个变体里只有当前设备需要的那个架构文件。
图片资源的优化,主要体现在删除无用图片和图片资源压缩这两方面。
清除无用图片资源
删除无用图片的过程,可以概括为下面这几步:
注意:对于"image_%d"这种方式的图片不要误删。
如果你不想自己重新写一个工具的话,可以选择开源的工具直接使用。我建议的有2个开源的工具比较好用:FengNiao和LSUnusedResources。关于这个两个工具的对比,大家可以参考:https://www.avanderlee.com/optimization/unused-images-clean-up/ 这篇文章。
清除重复图片资源
重复资源不是指命名重复而是内容相同。
fdupes 是Linux下的一个工具,可以在指定的目录及子目录中查找重复的文件。fdupes通过对比文件的MD5签名,以及逐字节比较文件来识别重复内容。
图片压缩
目前比较好的压缩方案是,将图片转成WebP。WebP是Google公司的一个开源项目。关于WebP的原理及好处已经在iOS启动优化之首屏图片加载优化这篇文章中写过了,感兴趣的同学可以查阅这篇文章。
Google公司在开源WebP时,提供了一个图片压缩工具cwebp来将其他图片转成WebP
值得注意的是:WebP在CPU消耗和解码时间上会比PNG高一些。所以,我们有时候还需要在性能和体积上做取舍。
所以要具体情况具体分析,如果图片较大,可以考虑使用WebP;而较小时,可以使用网页工具TinyPng或GUI工具ImageOptim进行图片压缩。这两个工具的压缩率没有WebP那么高,不会改变图片压缩方式,解析时对性能损耗也不会增加。
对代码进行瘦身,就是找到并删除无用的代码,查找无用代码的过程概括如下:
使用AppCode找出无用代码
通过AppCode可以检查未使用的文件,拼写问题,类型检查等多种潜在疑难杂症。
通过Code->Inspect Code进行静态分析:

使用App Code查找无用代码会存在一些弊端:
LinkMap结合Mach-O找无用代码
可以通过分析LinkMap来获得所有的类和方法的信息。获取LinkMap可以通过将Build Setting里的 Write Link Map File设置为Yes,然后指定Path to Link Map File的路径,就可以得到每次编译后的 LinkMap 文件了,设置选项如下所示:
LinkMap包含三部分:Object File、Section 和 Symbols。
Object File:包含了代码工程的所有文件;
Section:描述了代码段在生成的Mach-O里的偏移位置和大小;
Symbols:列出每个方法、类、block、以及它们的大小;
通过LinkMap ,不但可以统计出所有的方法和类,还能够清晰地看到代码所占包大小的具体,进而可以针对性地进行代码优化。
得到了代码的全集信息以后,还需要找到已使用的类和方法,获取到差集,从而找出无用代码。Mach-O文件中包含了所有使用过的类和方法。
iOS中的方法都是通过objc_msgSend来调用的,而objc_msgSend在Mach-O文件里是通过__objc_selrefs这个section来获取selector这个参数的,所以__objc_selrefs里的方法一定是被调用了的。__objc_classrefs里是被调用过的类,__objc_superrefs是调用过super的类。通过__objc_classrefs和__objc_superrefs,我们就可以找出使用过的类和子类。
可以使用MachOView这个软件来查看Mach-O文件里的信息。