AppStore 下载大小如果在 OTA 下载限制内增长,对用户新增、留存等指标影响不大。而一旦超过 OTA 下载限制,则对整体指标产生明显影响。之前统计的劣化数据指标:当限制在 150MB 并且无法下载的时候,对用户的新增有 10%的影响。由于 iOS13 限制的宽松化,所以在 iOS13 之后设备上这个数据将低于 10%。此数据仅供参考并不能一概而论,对于不同类型的 App 首次安装的场景会呈现差异,比如生活服务、出行类 App 对应蜂窝下载场景会多于影音类、游戏类 App。
其次对仍然需要支持 iOS8 以下的 App, 超出 __TEXT 段大小的限制将会很大程度上影响审核以及发版进度。当然可以通过一些手段进行救急,比如拆分动态库的方式绕过。但是这些手段可能导致安装包整体变得更大。
除了 Apple 的限制外,包大小的劣化一定程度上意味着更加慢的启动速度;更多的的代码逻辑;更低研发效率;过于复杂的代码还会带来对代码修改的风险将对稳定性产生负面影响;让性能等基础体验变差,所以包大小不是一个孤立的指标,它从侧面的反映出 App 的健康状态。
Part 2. 安装包的构成以及如何分析安装包
安装包的构成
当通过 Archieve 打包的安装包并 unzip 解压之后,通常可以看到如下的安装包结构:
-
Payload
-
- TheApp.app
-
OnDemandResources
-
Symbols
而主要影响下载和安装大小的内容都集中在 .app 中。而解压后的占用 .app 大部分的大小的文件如下:
-
主二进制(和.app 同名的 MachO 文件);
-
Frameworks(App 自身引入的动态库);
-
Plugins (App Extension 本质依然是动态的可执行文件);
-
xxx.lproj(原生的翻译资源);
-
各种资源 Bundle;
安装包分析
通过分析安装包,了解安装包中可执行文件占用大小、资源占用大小,了解安装包的现状。明确从哪里入手可以获得 ROI 最高的优化手段。而在做包大小分析过程中比较难的是,怎么样通过线下的安装包衡量对下载大小的影响。
但由于上传到 AppStore Connect 到之后,Apple 对安装包做了一些调整,线下安装包的变化无法对应到真正的下载大小变化的变更。而这部分调整包括:
-
App Slicing 对于不同架构的裁剪,可执行文件只剩下单架构;
-
Asset.car 中图片只留下设备需要的特定尺寸和压缩算法的变体;
-
二进制部分__TEXT 段的通过 FirePlay 进行加密导致 __TEXT 段的压缩比为 1( iOS 13+ 以上设备下载变体中苹果移除了这个加密 );
所以线下评估的时候,通过删除 Asset.car 中图片带来 10MB 的包大小的减小,但对最后的下载大小影响可能远远小于 10MB 。而当增加的 2MB 的代码 ,最后的下载大小实打实地增长了 2MB。
可执行文件分析
安装包中的可执行文件,占了安装包中很大一部分空间,而这部分不光和代码有关还和编译、链接过程中添加的参数,编译的机器环境、Xcode 版本等等都有关系。而常常通过 LinkMap 来对可执行文件进行分析。
LinkMap 中包含了可执行文件的架构信息,段表,链接了的所有文件,以及文件中各符号占用的大小。其实通过分析 LinkMap 就基本得到了可执行文件中包含了哪些东西。这部分数据也有助于针对性的进行一些优化。
Part 3. 常见的包大小优化手段
可执行文件部分的优化
重命名部分段绕过 __TEXT 段 FirePlay 加密:
虽然 Apple 在 iOS13 + 去掉了对可执行文件的 __TEXT 段加密,但对于 iOS 低版本的设备而言超出 OTA 的下载限制比高版本影响还要大。所以可以将可执行文件中一部分段从 __TEXT 段中移动到其他段来绕过加密带来提高压缩比。而且在启动时候 Page Load 解密 __TEXT 段也是比较大的性能损耗,能同时优化启动时间。目前比较稳定的可以移动的段包括:
__TEXT,__cstring
__TEXT,__const
__TEXT,__gcc_except_tab
__TEXT,__objc_methname
__TEXT,__objc_classname
__TEXT,__objc_methtype
可在OTHER_LDFLAGS
中添加如下参数进行移动:
$(inherited) -Wl,-
r