查找iOS上每个外部库贡献的大小



我试图减少我的应用商店二进制文件的大小,我们有很多外部库,可能有助于最终ipa的大小。

所有这些信息都包含在链接图中,如果你有耐心筛选它(对于大型应用程序,它可能相当大)。链接地图有一个所有库的列表,它们的对象文件,以及打包到你的应用程序中的所有符号,都是人类可读的文本。通常,默认情况下,项目不会被配置为生成它们,因此您必须快速更改项目文件。

From From Xcode:

  1. 在目标的"构建设置"下,搜索"地图"
  2. 在下面的结果中,在"链接"部分,将"写入链接地图文件"设置为"是"
  3. 请务必注意"链接地图文件路径"下列出的完整路径和文件名

下次你构建你的应用程序时,你会得到一个链接映射转储到该文件路径。请注意,路径是相对于你的应用程序的位置在DerivedData文件夹(通常是~/Library/Developer/Xcode/DerivedData/<your-app-name>-<random-string-of-letters-and-numbers>/Build/Intermediates/...,但YMMV)。因为它只是一个文本文件,你可以用任何文本编辑器来读取它。

链接图的内容分为3部分,其中2部分将与您要查找的内容相关:

  1. Object Files:这部分包含了最终应用程序中包含的所有对象文件的列表,包括你自己的代码和你包含的任何第三方库的代码。重要的是,每个对象文件还列出了它来自的库;
  2. Sections:这部分,与你的问题无关,包含处理器段及其Sections的列表;
  3. Symbols:这部分包含你感兴趣的原始数据:所有符号/方法的列表,以及它们的绝对位置(即处理器内存映射中的地址),大小,最重要的是,对它们包含的对象模块的交叉引用(在'File'列下)。

从这些原始数据中,您可以获得进行所需大小计算所需的一切。从第一条,你可以看到,对于每个库,有N个可能的组成对象模块;从#2中,你可以看到,对于每个对象模块,有M个可能的符号,每个符号占用大小S。对于任何给定的库,那么你的粗略大小顺序将是O(N * M * S)这样的东西。这只是给你一个将进入你的实际计算的组件的指示,它不是任何有用的公式。要执行计算本身,我很抱歉地说,我不知道有任何现有的工具可以为您完成必要的处理,但是考虑到链接映射只是一个文本文件,使用一点脚本魔法和独创性,您可以构造一个脚本来完成繁重的工作。

例如,我有一个链接到以下库的小示例项目:https://github.com/ColinEberhardt/LinqToObjectiveC(示例项目本身来自ReactiveCocoa的一个很好的教程,在这里:http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1),我想知道它占用了多少空间。我已经生成了一个链接地图TwitterInstant-LinkMap-normal-x86_64.txt(它在模拟器中运行)。为了找到库中包含的所有对象模块,我这样做:

$ grep -i "libLinqToObjectiveC.a" TwitterInstant-LinkMap-normal-x86_64.txt

,它给了我这个:

[  8] /Users/XXX/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(LinqToObjectiveC-dummy.o)
[  9] /Users/XXX/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(NSArray+LinqExtensions.o)
[ 10] /Users/XXX/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(NSDictionary+LinqExtensions.o)

第一列包含我需要的符号表的交叉引用,所以我可以搜索它们:

$ cat TwitterInstant-LinkMap-normal-x86_64.txt | grep -e "[  8]"

得到:

0x100087161 0x0000001B  [  8] literal string: PodsDummy_LinqToObjectiveC
0x1000920B8 0x00000008  [  8] anon
0x100093658 0x00000048  [  8] l_OBJC_METACLASS_RO_$_PodsDummy_LinqToObjectiveC
0x1000936A0 0x00000048  [  8] l_OBJC_CLASS_RO_$_PodsDummy_LinqToObjectiveC
0x10009F0A8 0x00000028  [  8] _OBJC_METACLASS_$_PodsDummy_LinqToObjectiveC
0x10009F0D0 0x00000028  [  8] _OBJC_CLASS_$_PodsDummy_LinqToObjectiveC

第二列包含所讨论的符号的大小(十六进制),所以如果我把它们全部加起来,我得到0x103,或259字节。

更好的是,我可以做一些流黑客来减少它的基本元素,并为我做添加:

$ cat TwitterInstant-LinkMap-normal-x86_64.txt | grep -e "[  8]" | grep -e "0x" | awk '{print $2}' | xargs printf "%dn" | paste -sd+ - | bc

直接给出数字:

259

"[ 9]"(13016字节)和"[ 10]"(5503字节)做同样的处理,并将它们添加到前面的259字节,得到18778字节。

您当然可以改进我在这里所做的流黑客,使其更加健壮(在此实现中,您必须确保获得正确的空格数量并引用括号),但您至少了解了这个想法。

为你的应用制作一个。ipa文件并保存在你的系统中。

打开终端,执行如下命令:

unzip -lv/path/to/your/app.ipa

它将返回一个关于.ipa文件的数据表。size列包含.ipa文件中每个文件的压缩大小。

我想你应该能够从中提取出你需要的信息:

符号-w -noSources YourFileHere

裁判:https://devforums.apple.com/message/926442 # 926442

IIRC,它不会给你关于每个库的明确摘要信息,但你应该发现每个库的函数应该聚集在一起,所以你可以计算出每个库的大致贡献:

还要确保你在构建设置中将Generate Debug Symbols设置为NO。这可以将静态库的大小减少约30%。

如果它是您关心的一部分,静态库只是相关的。o文件归档在一起加上一些记账。所以一个1.7mb的静态库——即使其中的代码占了整个1.7mb——通常不会给你的产品增加1.7mb的空间。关于死代码剥离的通常规则仍然适用。

除此之外,您还可以减少代码的构建大小。以下可能不是一个全面的列表。

在目标的构建设置中寻找"优化级别"。通过将其切换为"最快,最小- o",您将允许编译器为大小牺牲一些速度。

确保您正在为拇指构建更紧凑的ARM代码。假设你使用的是LLVM,这意味着确保你的项目设置中没有-mno-thumb。

还要考虑您想要为哪个体系结构构建。苹果不允许同时支持ARMv6和iPhone 5屏幕的应用提交,并且已经从最新的Xcode中完全放弃了ARMv6支持。所以现在可能没有必要写这些

最新更新