缩减iOS安装包大小是不少中大型APP都要作的事,通常首先会对资源文件下手,压缩图片/音频,去除没必要要的资源。这些资源优化作完后,咱们还能够尝试对可执行文件进行瘦身,项目越大,可执行文件占用的体积越大,又由于AppStore会对可执行文件加密,致使可执行文件的压缩率低,压缩后可执行文件占整个APP安装包的体积比例大约有80%~90%,仍是挺值得优化的。下面介绍一下在研究可执行文件过程当中发现的能够优化的点。研究的过程使用了linkmap,linkmap的介绍跟生成能够参考另外一篇文章—iOS可执行文件的组成。node
1.编译器优化级别git
Build Settings->Optimization Level有几个编译优化选项,release版应该选择Fastest, Smalllest,这个选项会开启那些不增长代码大小的所有优化,并让可执行文件尽量小。github
2.去除符号信息安全
Strip Debug Symbols During Copy 和 Symbols Hidden by Default 在release版本应该设为yes,能够去除没必要要的调试符号。Symbols Hidden by Default会把全部符号都定义成”private extern”,具体意思和做用我还不清楚,有待研究,但设了后会减少体积。这些选项目前都是XCode默认选项,但旧版XCode生成的项目可能不是,能够检查一下。app
其余优化还能够参考苹果的官方文档—CodeFootprint.pdf优化
项目里会引入不少第三方静态库,若是能知道这些第三方库在可执行文件里占用的大小,就能够评估是否值得去找替代方案去掉这个第三方库。咱们能够从linkmap中统计出这个信息,我写了个node.js脚本,能够经过linkmap统计每一个.o目标文件占用的体积和每一个.a静态库占用的体积,并进行排序。详见这里(需FQ)。ui
有人提出用ARC写的代码编译出来的可执行文件是会比用MRC大的,缘由大体是ARC代码会在某些状况多出一些retain和release的指令,例如调用一个方法,它返回的对象会被retain,退出做用域后会被release,MRC就不须要,汇编指令变多,机器码变多,可执行文件就变大了。还有其余细节实现的区别,先不纠结了。加密
那用ARC究竟会增大多少体积?我以为从汇编指令的增多减小去算是很难算准确的,这东西涉及细节太多,仍是得从统计的角度计算。作了几个对比试验,统计了几个同时支持ARC/MRC的开源项目在开启/关闭ARC的状况下__TEXT代码段的大小对比。只对比__TEXT代码段是由于:.net
ARC对可执行文件大小的影响几乎都是在代码段调试
可执行文件会进行某种对齐,例若有些段在不足32K的时候填充0直到对齐32K,若用可执行文件大小对比结果多是对齐后的,不许确。
实验数据:
结果是ARC大概会使代码段增长10%的size,考虑代码段占可执行文件大约有80%,估计对整个可执行文件的影响会是8%。
能够评估一下8%的体积降低是否是值得把项目里某些模块改为MRC,这样程序的维护成本上升了,通常不到特殊状况不建议这么作。
在项目里新建一个类,给它添加几个方法,但不要在任何地方import它,build完项目后观察linkmap,你会发现这个类仍是被编译进可执行文件了。
按C++的经验,没有被使用到的类和方法编译器都会优化掉,不会编进最终的可执行文件,但object-c不同,由于object-c的动态特性,它能够经过类和方法名反射得到这个类和方法进行调用,因此就算在代码里某个类没被使用到,编译器也无法保证这个类不会在运行时经过反射去调用,因此只要是在项目里的文件,不管是否又被使用到都会被编译进可执行文件。
对此咱们能够经过脚本,遍历整个项目的文件,找出全部没有被引用的类文件和没有被调用的方法,在保证没有其余地方动态调用的状况下把它们去掉。若是整个项目历时很长,历时代码遗留较多,这个清理对可执行文件省出的空间仍是挺可观的。
观察linkmap能够发现每一个类和方法名都在__cstring段里都存了相应的字符串值,因此类和方法名的长短也是对可执行文件大小是有影响的,缘由仍是object-c的动态特性,由于须要经过类/方法名反射找到这个类/方法进行调用,object-c对象模型会把类名,方法名列表都保存下来。
能够考虑在编译前把全部类和方法名进行混淆,把长名字替换成短名字,这样作的好处除了缩小体积外,还对安全性有很大提高,别人拿到可执行文件对它class-dump出来的结果都是混淆后的类和方法名,就没法从类和方法名中猜出某个方法是作什么的,就难以挂钩子进行hack。不过这样有个缺点就是crash堆栈反解出来的堆栈方法名会是混淆后的,须要再加一层混淆->原名的转换,实现和使用成本有点高。
实际上这部分占用的长度比较小,中型项目也就几百K,对安全性要求高的状况能够试试。
代码上定义的全部静态字符串都会记录在在可执行文件的__cstring段,若是项目里Log很是多,这个空间占用也是可观的,也有几百K的大小,能够考虑清理全部冗余的字符串。另外若是有特别长的字符串,建议抽离保存成静态文件,由于AppStore对可执行文件加密致使压缩率低,特别长的字符串抽离成静态资源文件后压缩率会比在可执行文件里高不少。
最后简单把缩减iOS安装包大小的各类方法列出来做为CheckList: