Unity3D打包中优化iOS包大小

有过App Store提审经验的童鞋应该知道,App Store对iOS提审包有一个包体大小的限制,这个限制不仅仅是对Mach-O可执行文件大小限制,还有整包大小的限制,比如“80M”、“150M”,这些包体大小的限制会直接影响到你APP能否成功上传或者玩家方便下载。App Store官方文档中规定,对于整包大小超过150M的App包,可以上传到App Store并发布,但是无法在移动网络下下载,必须在Wifi网络下才能下载;而对于Mach-O可执行文件大小的限制则依据iOS版本有不同的要求,具体如下图:

Unity3D打包中优化iOS包大小_第1张图片

简单理解就是:

  • 对于iOS7.0以下版本的App,32位+64位指令集的可执行文件之和最大为80M;
  • 对于iOS7.x-iOS8.x版本的App,32位或64位指令集的可执行文件大小都不超过60M;
  • 对于iOS9.0以上版本的App,32位+64位指令集的可执行文件之和最大为500M。

那么怎么查看Mach-O可执行文件的大小呢?上图也给出了答案,解压ipa包,找到app_name.app/app_name就是可执行文件,使用size命令查看一下该文件,即可看到__TEXT部分的大小。

之前对项目Unity升级使支持iOS64位的时候就遇到了一次可执行文件大小超过80M的上传失败,查了下原因,原来是因为Unity4.6.2及之后的版本使用了新的IL2CPP技术,使得最终编译的可执行文件大小激增。测试发现,Unity4.6.2以及之后的几个版本IL2CPP技术还是有挺大的差异,这也导致生成出来的执行文件大小差异比较大,不过不管怎么样项目的可执行文件还是超过80M,不得不对可执行文件的大小进行优化,参考了Unity3D的官方文档和App Store官方优化文档,做了一些整理总结。

先讲下怎么优化iOS包可执行文件的大小:

  1. 使用Release版本打包最终发布包,并确保Release模式下的Optimization Level为 Fastest, Smallest [-Os]
  2. Unity的Build Player Setting中,把 Stripping Level 改为 Use micro mscorlib; Stripping Level 有三个等级选项:Strip assemblies,Strip ByteCode 和 Use micro mscorlib。Strip assemblies 等级下,在AOT编译阶段通过分析字节码将未被引用的类或者方法从dll中移除;Strip ByteCode 等级下,所有的.net dll将被剥离为元数据,因为所有代码在AOT阶段已经预编译并链接到主二进制文件中;Use micro mscorlib 等级下,一些组件将从此库中删除,例如Security、Reflection.Emit、Remoting等,内部组件之间的相互依赖性也将最小化。此优化减少了主二进制文件和mscorlib.dll的大小,但它与某些system和system.xml程序集类不兼容,因此请小心使用它。以上三种等级优化是相互累计叠加的,即等级2包含等级1,等级3包含等级2。
  3. Unity的Build Player Setting中,当 Scripting backend 选择 IL2CPP 时,勾选Strip Engine Code;勾选该选项,本地Unity引擎中没有使用的模块和类将被剔除,这有可能导致某些第三方库使用到而该模块或类被删除而有可能导致App闪退。此时Unity有提供了一个配置方案,可以避免被剔除,只需要在Assets目录下添加link.xml,在里面添加不想被剔除的dll的名字。
  4. Unity的Build Player Setting中,把 Api Compatibility Level 选择 .net 2.0 subset
  5. Unity的Build Player Setting中,把 Script call optimization level 选择成 Fast but no exceptions
  6. 删除没用或重复引用的第三方库,或者使用轻量级的第三方库代替原先引用库,比如使用轻量级的json库,如LitJSON;
  7. 删除没用代码,比如一些第三方库的Example代码,废弃的系统代码等,通过分析LinkMap文件可以得到Mach-O可执行文件中各个类或库的大小(设置Project->Build Settings->Write Link Map File为YES,并设置Path to Link Map File,build完后就可以在设置的路径看到LinkMap文件了),使用这个工具可以检测无用的OC类,使用这个工具可以得到各个类或库的大小,然后着重优化相应的模块;
  8. 移除非必须使用的.net基础库,使用其它更精简的库代替,如System.xml可以用XMLParser或SecurityParser替代(可减少3-5M),System.Linq也尽量不用,其一是容量问题,其二是效率问题,其三是在iphone4s下面可能导致crash的问题。
  9. 分离代码和资源,将资源(如长字符串,表格等)从代码中剥离并将它们放在外部文件中,因为外部文件的压缩效率比将数据编译为二进制文件时要高;
  10. 少用或不用模板,如List,Dictionary这种泛型容器,因为他们会使得il2cpp产生大量代码,提取静态字段,可以把静态字段数组管理,再通过id映射,这个在XLua官方文档中的Hotfix Flag的IntKey标签上看到类似做法的,具体原因应该也是和il2cpp生成代码有关,具体原因如果有知道的小伙伴麻烦评论告知;
  11. 提升iOS的版本,移除不支持的指令集,如不支持armv7则不选择。

根据Unity官方文档描述,一个空Unity项目,如果没有开启包大小优化大概是22M,开启上述优化之后大概是12M,还是有比较大的优化效果的。

一个游戏App中,不用说资源的大小肯定占大头,接下来说下优化iOS包的资源:

  1. 剔除没有使用的图片,对于重复使用的图片新建公共图集;
  2. 使用8bit的png图片代替32bit的png图片或者pvrtc图片;这一步可以省下很大的包大小,因为游戏中很多资源都是32bit的png格式,而一张图片压缩后可以省下1/4的空间。但是也不是所有的png都能压缩成8bit格式,8bit的png图片只有256种不同的颜色,对于照片细节要求很高的就不能使用。png图片压缩可以考虑pngquant这一开源工具,可以使用命令行实现一键打包压缩。
  3. 压缩音效资源,可以使用 MP3格式压缩,这格式目前在Android和iOS上都可以支持,不然还需要处理不同平台的音频转换;
  4. 优化mesh文件,使得单个模型片面数<3000,材质数<3,骨骼数<50。

根据App Store官方文档可知,Xcode 提供可App包大小报告,你只需要:

  1. 创建App包档案(Archive),选择 Product > Archive;
  2. 导出App包,在档案管理器(Archives organizer)界面选择导出档案,点击发布;
  3. 选择“Export for specific devices”,在下拉菜单中选择“All compatible device variants”;
  4. 选择“Rebuild from bitcode”。

这样你就能在导出文件夹中找到“ App Thinning Size Report.txt”这样一个文件,里面包含了每个设备类型的压缩和未压缩包(加上必须资源)的大小。 这个文档的包大小只是一个估计的包在App Store上大小,因为发布过程中ipa包会被进一步加密,这个加密过程会导致包还会稍微再大一些。

参考:

Unity引擎IOS执行档大小优化

ipa包大小之linkMap文件分析

关于ios的ipa包的分析之link map 文件的分析

基于LinkMap分析iOSAPP各模块体积

你可能感兴趣的:(游戏开发)