一种大幅减少iOS应用程序下载量的快速方法

在阅读本文之前:Apple表示将通过不同的“打包”方式将所有应用程序的下载大小减少50%。 他们可能正在解决本文提供的解决方法的问题,从而使本文无关紧要。 但是,我将把这篇文章留给大家关注。

应用下载大小很重要。 应用程序的下载大小越大,用户下载的用户就越少。 此外,如果超过150 MB,则App Store将不允许用户通过WWAN下载它。

什么决定了应用程序的下载大小?

让我们看一下Telegram应用程序(为iPhone X精简),看看每种文件类型贡献了多少:

如您所见,它由二进制文件(主要的二进制文件,框架和扩展二进制文件)主导。 二进制文件通常占应用程序下载大小的60%以上。

为什么我的二进制文件这么大? 真的有那么多代码吗? 猜猜是因为我是10倍程序员😏

代码当然可以加起来,但是部分问题在于,Apple在将二进制文件的大部分添加到用户下载的压缩有效载荷之前对其进行了加密。 加密数据在压缩程序中看起来像随机数据,因此它根本无法对其进行压缩。

但是加密是好的,因为它会使我的应用程序更防篡改,对吗?

实际上,加密几乎没有用! 您可以借助Clutch轻松地在越狱的手机上解密任何应用程序。 另外,防篡改对您的应用程序有多重要?

加密增加了多少?

对于典型的应用程序,加密部分约占二进制文件的70%(而二进制文件又占应用程序的80%)。 如果未加密然后再压缩,则其大小将减少约60%。 因此,我们拥有60%的80%中的70%,即将您的应用程序总体大小减少了34% 。 您可以使用此脚本来估算节省的费用。 您可以在下面的“ iOS二进制文件概述”部分中找到有关加密内容的更多详细信息。

结论:您的用户正在下载大量的应用程序有效负载,毫无收获!

解决方案:将所有内容移出二进制文件的加密部分

iOS二进制文件概述

每个二进制文件都组织成许多称为段的块。 每个段均包含多个部分。 这里有一段代码,一段是常量字符串,等等。Apple加密__TEXT段,仅此而已。 如果我们将所有部分移出该段,则该段将几乎不占用空间,并且对其进行加密不会对我们的应用产生太大影响。 可以将这些部分移到新的段,在这些段中它们不会被加密并且可以正确压缩。 我们应用的解压缩大小不会改变,但压缩大小会改变。

为什么不完全摆脱__TEXT ? 可能有一种方法可以完成,但是当我尝试时,我遇到了许多问题,因此我们只介绍这些部分。

1.禁用位码(如果已启用)

我们的链接器标志不适用于位码,因此我们必须关闭位码。 关闭位码有什么缺点吗? 我认为,不是真的,但是想要了解更多信息,请通读本文。 另外,如果您决定要在以后的发行中使用位码,则始终可以撤消该技巧。

2.检查您应用的当前状态

从构建日志获取可执行文件的路径:

然后,运行xcrun size -x -l -m ,您应该获得:

 段__PAGEZERO:0x100000000(vmaddr 0x0 fileoff 0) 
 段__TEXT:0x8000(vmaddr 0x100000000 fileoff 0) 
  __text部分:0x1fb0(地址0x10000407c偏移量16508) 
  __stub部分:0x240(地址0x10000602c偏移量24620) 
  ...更多部分 
 段__DATA:0x4000(vmaddr 0x100008000 fileoff 32768) 
  ... 

我们可以看到__TEXT段有很多节(在__TEXT段下面的行Segment __TEXT: ...Segment __DATA: ...上面的行)。

3.找出链接器标志

我们将新段__MY_TEXT 。 对于__TEXT段中的每个节,我们将在链接器调用中添加一个标志-rename_section __TEXT

__MY_TEXT

。 另外,我们需要添加-segprot __MY_TEXT rx rx来赋予我们的新段rx权限(读取和执行,但不写入)。 最后,要在Xcode构建期间将标志传递给链接器,需要将其从更改为-Wl,,,…

您可以快速获得一组标志,这些标志可能可以利用此要点完成任务。 或者,您可以更彻底地为二进制文件运行此脚本,这将为您提供所有部分的标志。

要添加这些标志,请转到目标的Xcode构建设置,并将其添加到“其他链接器标志”下:

4.验证

现在运行另一个构建并再次运行xcrun size …命令以查看它是否有效。 您应该看到类似以下内容:

 段__PAGEZERO:0x100000000(vmaddr 0x0 fileoff 0) 
 段__TEXT:0x4000(vmaddr 0x100000000 fileoff 0) 
 段__DATA:0x4000(vmaddr 0x100004000 fileoff 16384) 
  __got部分:0x88(地址0x100004000偏移量16384) 
  __la_symbol_ptr部分:0x180(地址0x100004088偏移16520) 
  ...更多部分 
 段__MY_TEXT:0x4000(vmaddr 0x100008000 fileoff 32768) 
  __text部分:0x1fb0(地址0x100008000偏移量32768) 
  __objc_methname部分:0xa2a(地址0x100009fb0偏移40880) 
  ...先前在__TEXT中的所有部分 
 段__LINKEDIT:0x10000(vmaddr 0x10000c000 fileoff 49152) 
 总计0x10001c000 

注意:根据我的经验, __const节并不总是移动的。 哦,好吧,这并不是一个很大的部分。

5.必要时冲洗并重复其他二进制程序

尽管到目前为止,对主二进制文件执行此操作通常是最大的胜利,但如果有的话,也可以对应用程序中的其他二进制文件执行此操作。 我想到的两个类别是应用程序扩展(例如共享扩展)和动态库AKA dylib(例如Swift dylib)。 对于扩展,您可以简单地重复以上过程。 对于dylib,只有您自己为它们进行链接时,您才能重复上述过程(这意味着您不能对Swift dylib执行此操作)。 我还没有测试过其他二进制文件的过程,但是我想它会同样顺利。

瞧!

现在,您已经拥有一个可以正确压缩的应用程序,其安全性成本最低。 如果您想再次检查用户正在下载什么,则可以将该应用程序下载到越狱的手机或桌面上(通过iTunes)。

免责声明

我已经使用我的一个应用程序进行了验证,可以使用正确压缩的二进制文件将其分发到App Store上并且仍然可以使用。 我还玩过符号化和Objective-C内省,它们似乎也起作用。 但是 ,我不能保证这是无风险的。 某些库中某些疯狂的运行时事物可能会受到此影响。 另外,苹果可能有一天会开始拒绝使用该技术的应用程序。 使用风险自负。

尽管如此,我还是建议您对具有良好Beta测试过程的任何应用程序进行尝试。 如果您决定尝试一下,请在评论部分告诉我它的运行方式!

进一步阅读

二进制大小的更多优化
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/CodeFootprint/CodeFootprint.html

Mach-O可执行文件概述
https://www.objc.io/issues/6-build-tools/mach-o-executables/

OSX上的man ld ,链接程序的手册页,其中包含很多很酷的标志

特别感谢Jeb Boniakowski对本文的反馈。