摘要
苹果对 iOS App 大小有严格限制:下载大小超限会阻碍用户在蜂窝网络下载 App ,直接影响新用户转化;可执行文件超限将导致 App 审核被拒,直接影响上架。今日头条探索实践 __TEXT 段迁移技术,成功减小下载大小 32%,并且解决了可执行文件大小受限问题。
一、背景知识
1. 下载大小限制
App 大小有下载大小和安装大小的概念。
下载大小是指 App 压缩包(也就是 .ipa 文件)所占的空间,用户在下载 App 时,下载的是压缩包,这样做可以节省流量;当压缩包下载完成后,就会自动解压,解压过程也就是通常所说的安装过程;安装大小就是指压缩包解压后所占用的空间。
安装大小在 App Store 上就可以看见 ,通常它会影响用户的下载意愿:
而下载大小只有研发人员在 App Store Connect 后台才可以看,用户看不见,它影响的是下载消耗的流量和时长:
若下载大小超过限制,将无法使用蜂窝网络下载 App( iOS 13 之前),会收到文件容量太大的提示,需通过 Wi-Fi 网络下载。如下,为苹果历年来对 App 下载大小限制的变化情况:
-
2008 年 7 月,搭载了 App Store 的 iPhone 3G 正式发售,下载限制仅为 10 MB
-
2010 年 2 月,苹果将 iPhone 3G 的下载限制从 10 MB 提升到 20 MB
-
2012 年 3 月,iOS 5.1 正式版后,下载限制从 20 MB 提升到 50 MB
-
2013 年 9 月,iOS 7 正式版后,下载限制从 50 MB 提升至 100 MB
-
2017 年 9 月,iOS 11 正式版后,下载限制从 100 MB 提升至 150 MB
-
2019 年 5 月,下载限制从 150 MB 提升至 200 MB
-
2019 年 9 月,iOS 13 正式版后,若下载大小超过 200 MB,用户可选择是否使用蜂窝网络下载
如今,App 下载大小超出 200 MB 时 ,会出现两种情况:
-
iOS 13 以下的用户,无法通过蜂窝数据下载 App
-
iOS 13 及以上的用户,需要手动设置才可以使用蜂窝网络下载 App
2. 可执行文件大小限制
根据最大构建版本文件大小[1]描述,苹果对可执行文件大小亦有明确限制,超过该限制会导致 App 审核被拒:
ERROR: ERROR ITMS-90122: "Invalid ExecutaBe Size. The size of your app's executaBe file 'News.app/News' is 68534272 bytes for architecture 'arm64', which exceeds the maximum allowed size of 60 MB."
具体限制如下:
-
iOS 7 之前,二进制文件中所有的
__TEXT段总和不得超过 80 MB
-
iOS 7.X 至 iOS 8.X ,二进制文件中,每个特定架构中的
__TEXT段不得超过 60 MB
-
iOS 9.0 之后,二进制文件中所有的
__TEXT段总和不得超过 500 MB
二、面临问题
随着网络普及、流量费用降低,苹果已经放宽了限制。但下载大小若超出 200 MB,可以肯定对新增仍会有一定影响。这对上亿级用户的 App 来说是巨大的损失,并且本着追求极致、在竞品中拔得头筹的理念,我们认为下载大小 200 MB 是包大小的一根红线。
今日头条 App 的下载大小已经接近 180 MB,而经过了多年的极致优化(包括但不限于代码/图片/其它资源的优化、编译/链接参数的优化、推进无用业务下线、准入卡口等),已经很难再有较大幅度的减少。为此平台和各方都投入了极大的人力、甚至牺牲了业务的迭代空间来优化/抑制下载大小。
2020 年下半年,我们另辟蹊径探索实践了 __TEXT 段迁移的方法:将可执行文件的 __TEXT 段中的部分节移动到其它的段,避开苹果的加密机制,提高了可执行文件的压缩效率,使 App 的下载大小减少了 60 MB。
该方案彻底解决了下载大小限制的问题,同时还解决了仍在支持 iOS 8.X 的 App 面临的可执行文件大小限制问题。
三、技术原理
1. Mach-O 文件格式简介
iOS 可执行文件是 Mach-O 格式,主要由 Header、Load Commands、Data 三部分。
可以简单认为:
-
Header描述了文件的大概信息。
-
Load Commands由多条Load Command组成,它们描述了Data在二进制文件和虚拟内存中的布局信息,有了这个布局信息就能够知道Data在二进制文件中和虚拟内存中是怎样排布的,它相当于修房子时的图纸一样。
-
Data存储了实际的内容,主要是程序的指令和数据,它们的排布完全依照Load Commands的描述。
Mach-O 文件中的 Data 部分主要是以 Segment(中文翻译为段)和 Section (中文翻译为节)的方式来组织内容的,好比学校中有年级和班级、公司中有部门和小组一样,把有共同特点的内容组织到一块,可以方便管理,提高效率。
使用 $ xcrun size -lm <binary-path> 指令可以查看 Mach-O 文件 Data 部分的结构和各 Segment/Section 的大小信息(该 Mach-O 文件由 Xcode 的 iOS App 模板工程构建而来)。在不需要更详细的信息时,这条命令很方便。
上图就展示了 Data 中的内容排布的基本信息。
由该图可知,在该文件中:
-
Data部分中有 5 个 Segment,依次是:-
__PAGEZERO -
__TEXT -
__DATA_CONST -
__DATA -
__LINKEDIT
-
-
除
__PAGEZERO和__LINKEDIT外,每个段中有多个Section。
注意:
Data与__DATA是不同的两个概念。Data是 Mach-O 文件中的一部分,包含多个段。__DATA只是Data中的一个段。
__PAGEZERO 的大小是 4 GB,但并不是它在 Mach-O 文件中的真实大小。这 4 GB 是 Mach-O 加载进内存后, __PAGEZERO 在内存中占中的大小,它不可读,不可写,主要用来捕捉 NULL 指针的引用。如果访问 __PAGEZERO 段,会引起 EXC_BAD_ACCESS 错误。__PAGEZERO 在 Mach-O 中实际上并不占用 Data 部分的空间。
__TEXT、__DATA_CONST、__DATA 用于保存程序的代码指令和数据。
__LINKEDIT 包含启动 App 需要的信息,比如 bind & rebase 的地址,代码签名,符号表等。
2. __TEXT 段迁移的原理
程序的构建过程包含 预处理 -> 编译 -> 汇编 -> 链接 等 4 个主要阶段,完成之后就会得到 Mach-O 可执行文件。
通过 $ man ld ,可以发现链接器有一个参数: -rename_p orgSegment orgSection newSegment newSection。使用该参数可以将orgSegment/orgSection的名称修改为newSegment/newSection。
可以在 Other Linker Flags 中传递该参数。如:
-Wl,-rename_p,__TEXT,__text,__BD_TEXT,__text
-Wl,-segprot,__BD_TEXT,rx,rx

其中 -Wl 的作用是告诉 Xcode 它后面的参数是添加给 Ld 链接器的,这些参数将在链接阶段生效。
第一行参数会新创建一个 __BD_TEXT 段,并把 __TEXT,__text 移动到 __BD_TEXT,__text。
第二行参数是给 __BD_TEXT 赋予可读和可执行权限。
构建完成后再来看一下移动 __TEXT,__text 后的 Mach-O 文件:
可以看到 __TEXT,__text 已经被移动到了 __BD_TEXT 中去了,它的地址也由起始的 0x100005e5c 变为了 0x100010000 。此时程序仍可以正常的运行,这是因为操作系统只关心段的读/写/执行权限,并不关心段或节的名称。即便是使用了 -rename_p 移动 Segment/Section,各符号的地址也会由链接器修正好,因此段移动后程序也可以正常运行。
在最低支持 iOS 8 的时代,很多大型 App 都遇到过可执行文件中 __TEXT 段超 60 MB 的问题。facebook[2] 当时采用了 -rename_p 的技术来避免该问题。他们使用的链接参数为:
-Wl,-rename_p,__TEXT,__cstring,__RODATA,__cstring
-Wl,-rename_p,__TEXT,__gcc_except_tab,__RODATA,__gcc_except_tab
-Wl,-rename_p,__TEXT,__const,__RODATA,__const
-Wl,-rename_p,__TEXT,__objc_methname,__RODATA,__objc_methname
-Wl,-rename_p,__TEXT,__objc_classname,__RODATA,__objc_classname
-Wl,-rename_p,__TEXT,__objc_methtype,__RODATA,__objc_methtype
参数的作用是将 __TEXT 中的 __cstring、__gcc_except_tab、__const、__objc_methname、__objc_classname、__objc_methtype<

苹果对iOS App大小有下载和可执行文件大小限制,影响用户下载和App上架。今日头条探索实践__TEXT段迁移技术,将可执行文件的__TEXT段部分节移到其他段,避开加密机制,提高压缩效率,减小下载大小32%,解决了相关限制问题,并分享实践中问题的解决办法。
最低0.47元/天 解锁文章
2万+

被折叠的 条评论
为什么被折叠?



