我试图减少我的应用商店二进制文件大小,我们有很多外部库可能会影响最终ipa的大小。有没有办法找出每个外部静态库在最终二进制文件中占用多少(除了去除每个外部静态库?)?
答案 0 :(得分:19)
所有这些信息都包含在链接地图中,如果您有耐心筛选它(对于大型应用程序,它可能非常大)。链接映射包含所有库,其目标文件以及打包到应用程序中的所有符号的列表,所有这些都是人类可读的文本。通常情况下,项目没有配置为默认生成它们,因此您必须快速更改项目文件。
从Xcode内部:
下次构建应用时,您将获得转储到该文件路径的链接映射。请注意,路径相对于应用在DerivedData文件夹中的位置(通常为~/Library/Developer/Xcode/DerivedData/<your-app-name>-<random-string-of-letters-and-numbers>/Build/Intermediates/...
,但为YMMV)。由于它只是一个文本文件,您可以使用任何文本编辑器阅读它。
链接地图的内容分为3个部分,其中2个部分与您正在寻找的内容相关:
从这些原始数据中,您可以获得进行所需大小计算所需的一切。从#1开始,您会看到,对于每个库,都有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/Smyrl/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(LinqToObjectiveC-dummy.o)
[ 9] /Users/Smyrl/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(NSArray+LinqExtensions.o)
[ 10] /Users/Smyrl/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 "%d\n" | paste -sd+ - | bc
直接给我这个号码:
259
对"\[ 9\]"
(13016字节)和"\[ 10\]"
(5503字节)执行相同操作,并将它们添加到之前的259字节,这给了我18778字节。
你当然可以改进我在这里做的流黑客攻击,使其更加强大(在这个实现中,你必须确保你得到正确的空格数并引用括号),但是你至少得到了这个主意。
答案 1 :(得分:4)
制作应用的.ipa文件并将其保存在系统中。
然后打开终端并执行以下命令:
unzip -lv /path/to/your/app.ipa
它将返回有关.ipa文件的数据表。 size列具有.ipa文件中每个文件的压缩大小。
答案 2 :(得分:0)
我认为你应该能够从中提取所需的信息:
symbols -w -noSources YourFileHere
IIRC,它不会给你关于每个lib的明确的摘要信息,但是你应该发现每个库中的函数应该聚集在一起,所以通过一些努力,你可以计算每个lib的近似贡献:答案 3 :(得分:0)
还要确保在构建设置中将“生成调试符号”设置为“否”。这可以将静态库的大小减少大约30%。
如果它是您关心的一部分,静态库只是存档在一起的相关.o文件加上一些簿记。因此,1.7mb静态库 - 即使其中的代码是整个1.7mb - 通常会为您的产品增加170mb。关于死代码剥离的通常规则将适用。
除此之外,您还可以减少代码的内置大小。以下可能不是一份全面的清单。
在目标的构建设置中查找“优化级别”&#39;。通过将其切换为最快,最小的-Os&#39;你允许编译器牺牲一些大小的速度。
确保您正在构建拇指,即更紧凑的ARM代码。假设您正在使用LLVM,这意味着确保您在项目设置中的任何位置都没有-mno-thumb。
还要考虑要构建哪些体系结构。 Apple不允许提交支持ARMv6和iPhone 5屏幕的应用程序,并完全放弃了最新Xcode的ARMv6支持。所以现在可能没有任何意义,包括此。