Unity减小安装包的体积(210MB减小到7MB)
概述
项目简介
由于是公司内做的项目,不方便开源,就只分享优化过程吧。
项目信息
逐日是一个移动端单机小游戏,使用Unity开发,目前已将项目使用的Unity升级到2019.4.14f1c1 (3e5991a5f6ba)
版本。
项目内容
在进行优化前,项目资源目录如下,可以看到,项目目录命名杂乱,包含很多需求迭代产生的旧资源、无用场景、未压缩的音视频等内容。
由于这次主要是对于安装包大小的一些尝试,所以就不会特别关注游戏逻辑,整体能加载完成,不Crash就OK,没有对游戏逻辑上花费过多精力,后面的过程中可能有小部分图被压糊了,有视频无法加载等问题,不影响缩包的最终结果。
未优化的包体大小
如图所示,使用新版UnityEditor直接打包之后,生成的游戏Apk大小为218MB,这对于一个只有两个关卡的小游戏而言,明显过于臃肿了,假如上架到GooglePlay之后,光下载内容所消耗的时间和流量就劝退了一部分用户(更何况,现在GooglePlay限制了安装包大小不能大于100M!)。所以,对于安装包大小的优化是势在必行的。
第一步:Assembly构建优化
使用IL2CPP代替Mono
- Mono使用即时(JIT)编译,并在运行时按需编译代码。
- IL2CPP使用提前(AOT)编译并在运行之前编译整个应用程序。
使用IL2CPP进行构建有助于提高运行速度,并减少包体大小,IL2CPP的工作流程如下图:
将ScriptingBackend设置为IL2CPP后,执行构建得到的安装包大小为210MB,比使用Mono少了8MB(这个项目里游戏逻辑不多,脚本比较少,对于较大的项目来说,使用IL的优势更大)
裁剪更多未使用的代码(不是特别推荐)
Unity有提供一个Managed Stripping Level
选项,可以在构建时裁减掉未使用的代码,这个选项又是那个可选级别,IL2CPP不能关闭这个选项并且默认级别为Low
。不同的裁剪级别对应的规则不同,裁减掉游泳的代码可能性越高,并且有可能无法检测到通过反射引用其他代码的情况,导致程序崩溃。
设置Managed Stripping Level=High
后,安装包大小为209M。
关于脚本构建优化
对于Android Platform,我对于一个空的Unity3D项目进行过如下打包测试:
构建设置 | ApkSize |
---|---|
默认(Mono_Release_DotNetStandard2.0) | 16.9 MB |
ScriptBackend使用IL2CPP | 6.38 MB |
StrippingLevel=High | 6.02 MB |
CompressMethod=LZ4HC | 5.96 MB |
GraphicApi只使用OpenGLES2(Android 2.2+都支持) | 5.73 MB |
再往下就很难减小了......
第二步:资源优化
分析资源大小的利器
在Editor中构建完成后,可以打开EditorLog,里面列出了在未压缩的情况下,不同类型资源的占比以及每个资源体积从大到小的排列,我们可以直接根据Log查找哪些资源比较大,针对性地处理:
移除未使用的资源
为什么把这一步放在资源优化的第一位?因为先去掉无用的资源后面打包会快很多嘛。。。测试一个属性就要重新打个包有时候甚至需要重新Import整个项目半小时的时间伤不起啊~
在GitHub上随便找了个资源清理工具UnityAssetCleaner,对项目中的无用资源进行了清理:
这个步骤直接让Assets目录的大小从1.27GB
减小到192MB
,由于资源没有放在Resource下,所以未引用的资源并没有打包到Apk中,这个步骤之后仅仅让包体大小减少到了208MB。
但是重新Import项目会快很多啊有木有~!这也看出来当时做的时候走了多少弯路。。。
去掉无用的场景
第一次用Unity做游戏时,关卡切换、各种UI面板都是使用独立的场景做的,明明可以用Prefab的> _ <
看了下游戏里的场景,没有需要删掉的。。。如果有无用的场景,删除掉也可以减少包体大小。
纹理尺寸压缩、视频音频质量压缩
在项目中,尽可能降低图片和音视频的质量,使用低质量高压缩率的压缩格式,不仅内存占用低、性能也更好;当出现质量不满足要求时,再逐步的提升尺寸和压缩格式来满足需要。Link→官方文档:不同平台下支持的压缩格式
要在不修改源文件的情况下修改尺寸,可以直接在Unity里调整:
如上图所示,游戏里的纹理都是按照最大尺寸来导入的,并且由于使用的是Sprite动画,导致一个动画就要使用很多纹理,所以首要的问题是把不同的图片调整到适当的尺寸,比如场景地图使用2048或1024,较大的Boss角色和树木使用512,小怪、小火球等纹理使用256或更小。
音效以及视频,也按照类似的方法,适当调低分辨率和码率(视频其实可以直接放CDN)。
调整完之后,重新打了个包,emmm...只有52MB了(当然,有一小部分纹理被我压糊了,适当调整之后最终结果其实相差不大)。
Sprite Atlas
多个NPTO的纹理拼合到一起组成一个POT型的图集有利于Unity压缩图片,更能节省空间。创建方式如下(Unity2019+版本默认不使用给纹理打Tag的方式创建图集,而是需要手动创建)
将游戏中大小、用途类似的纹理,添加到各自的图集中,重新打包,包体大小33M。
AssetBundle打包
这可能是缩小Apk大小的最好方案了......
总体流程概述
如果前面的一系列缩包方法都不能达到想要的效果,就可以考虑把资源单独打包拿出来,用户启动App时进行下载。
首先在Unity里给资源打标签,把资源分到对应的Bundle中。
然后执行构建AssetBundle脚本(脚本官网文档有提供),把AssetBundle包输出到指定路径。
详细过程
把场景使用Prefab代替
在优化的过程中我发现,Unity通过BuildSetting中的场景列表来查找所有依赖的资源,所以为了打出来独立的AssetBundle包并断开AssetBundle内的资源与Apk之间的依赖关系,就需要对场景做优化。
将场景中的内容简单粗暴地整合到一个GameObject内,制作成Prefab,用挂载Prefab的方式代替挂载场景,并删掉原来的场景,清理BuildSetting中的场景列表。这样就断开了AssetBundle内的资源与Apk之间的依赖。
实现入口脚本
我的办法是创建一个Init场景作为整个App的入口,里面只挂一个GameFramework脚本来执行一系列必要的AssetBundle加载过程、管理各个用于代替场景的Prefab。
这样修改之后,我们构建出来的Apk就只会包含一个空的场景,以及C#脚本构建产生的dll,大小最小能有前面所说的5MB!!!
打AssetBundle包
前面我们把资源和Apk之间的依赖关系切断了,但是我们还是要想办法把它们动态加载回去的,这种方法就是AssetBundle包。
给资源打标签的过程是非常繁琐的,所以就使用脚本自动化处理了,会自动给ResForBundle下的直接子目录按照目录名递归添加标签。
运行了BuildAssetBundle命令之后,我们就能在输出目录得到一系列相互依赖的AssetBundle文件了(也包括他们的manifest描述文件)。
动态加载AssetBundle
我们可以使用Unity提供的AssetBundle Api来动态把AssetBundle文件加载到内存里,并根据路径读取它们包含的资源,由于游戏内的资源比较少,大约20~30MB,所以我就直接放在StreamingAssets目录下了(关于这个目录,是和Resource一样特殊的存在,感兴趣的话可以直接查一下)
在GameFramework启动时就加载所有的AssetBundle,并挂载Scene_Start.prefab到场景中,这样我们的游戏流程又能正常走下去了。
当然这个过程中还有好多好多细节要处理:
比如需要用宏来判断是在编辑器中还是在移动端,从而采用不同的自定义ResourceLoad来加载资源(如果是编辑器的话直接使用AssetDatabase Api通过路径加载资源,移动端则采用上面提到的AssetBundle内的资源);
如何递归地给指定目录下的内容添加标签并自动维护它们;
优化结果
对场景进行精简优化,只保留一个入口场景加载AssetBundle和加载入口,构建后,Apk大小只有7M。
打出的AssetBundle可以在App启动时通过http拉取到本地,如果不嫌资源包大的话也可以直接放在StreamingAssets目录打到apk内。
缩包历程
直接上图好了:
KeyWorkds:Unity安装包体积优化,Unity减小安装包体积,Unity构建更小的Apk,Unity减小构建的安装包大小,Unity缩小安装包
Unity减小安装包的体积(210MB减小到7MB)的更多相关文章
- App竞品技术分析 (3)减小安装包的体积(转)
http://blog.csdn.net/JspAndAsp/article/details/49339403 1 从几件小事说起 春节在家帮姐姐的iPhone手机安装市面上形形色色的App,忘记她是 ...
- iOS 优化ipa包,减小安装包大小
https://www.jianshu.com/p/a49d59b01669 项目打包之后.ipa包的大小是118.9M,上传到App Store后iPhone6s上显示85.5M,下载时间太长,所以 ...
- Unity减少构建安装包的体积(210MB减小到7MB)
概述 项目简介 由于是公司内做的项目,不方便开源,就只分享优化过程吧. 项目信息 逐日是一个移动端单机小游戏,使用Unity开发,目前已将项目使用的Unity升级到2019.4.14f1c1 (3e5 ...
- react-electron 项目打包体积尽可能减小的方法
当一个react-electron项目做好之后就可以开始进行打包,首先就是打包react,这个自然不用多说,不过事先要记住一点,项目目录主进程文件main.js最好放在根目录,再执行打包命令 npm ...
- VMWare中Centos Minimal最小安装包安装后网络,ftp配置
1.官网下载centos Minimal安装包,安装. 2.使用ip addr命令查看后没有ip地址显示. 3.点击WMWare的编辑->虚拟网络编辑->选择vmnet0(Bridged) ...
- 基于Proxy思想的Android插件框架
意义 研究插件框架的意义在于下面几点: 减小安装包的体积,通过网络选择性地进行插件下发 模块化升级.减小网络流量 静默升级,用户无感知情况下进行升级 解决低版本号机型方法数超限导致无法安装的问题 代码 ...
- JDK源码调试
1.首先遇到了一个问题line unavailable,然后通过以下方式解决: http://blog.csdn.net/xuefeng0707/article/details/8738869 对于想 ...
- 编译JDK源代码【转】
用Eclipse Debug,当跟踪进jdk api里时(比如javax.swing包里的类),无法查看某些local filed的值.这是因为jdk里的代码在打包时删除了一些用于调试的信息,以减小安 ...
- [BUAA软工]Beta阶段测试报告
Beta阶段测试报告 Bug发现与报告 BUG 出现原因 解决方案 将shell加上编辑器UI以后,两边显示的文件不同步 两边的根目录不一致 修改编辑器获取根目录的函数,使其与shell的/home目 ...
随机推荐
- 《前端运维》三、Docker--1镜像与容器
一.基本概念 如果我们想要让软件运行起来,首先要保证操作系统的设置,其次还需要依赖各种组件和库的正确安装.那么虚拟机就是一种带环境安装的一种解决方案,它可以实现在一种操作系统里面运行另外一种操作系统, ...
- 【仿真】Carla之收集数据快速教程 (附完整代码) [7]
收集过程可视化展示,随后进入正文: 参考与前言 看到仿真群对这类任务下(用carla收集数据然后再做训练等) 需求量大,顺手马上写一个好了,首先收集数据需要考虑清楚: 收集什么数据,需要什么样的数据格 ...
- Apache Ranger安装部署
1.概述 Apache Ranger提供了一个集中式的安全管理框架,用户可以通过操作Ranger Admin页面来配置各种策略,从而实现对Hadoop生成组件,比如HDFS.YARN.Hive.HBa ...
- Linux(centos7)安装RabbitMQ
由于RabbitMQ是由Erlang语言开发的,所以我们需要体检安装erlang语言的环境 下载这三个安装包:https://www.aliyundrive.com/s/4AxfTepHjMD 执行安 ...
- ThreadPoolTaskExecutor原理、详解及案例
为什么要用线程池? 服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的. 构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请 ...
- kafka 为什么那么快?
Cache Filesystem Cache PageCache缓存 顺序写 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快. Zero-copy 零拷⻉技术减少拷贝 ...
- spring-boot关于spring全注解IOC
什么是IOC容器: Spring IoC 容器是一个管理Bean 的容器,在S pring 的定义中,它要求所有的IoC 容器都需要实现接口BeanFactory ,它是一个顶级容器接口 IoC 是一 ...
- java后端使用token处理表单重复提交
保证接口幂等性,表单重复提交 前台解决方案:提交后按钮禁用.置灰.页面出现遮罩后台解决方案: 使用token,每个token只能使用一次1.在调用接口之前生成对应的Token,存放至redis 2 ...
- JVM的基础知识
一.JVM的基础知识 1.JVM内存结构: 1.JVM堆内存结构: 2.JVM内存分配: 3.Java的堆机构和垃圾回收: 4.Jvm堆内存配置参数: 5.JVM新生代概念和配置: 6.JVM老生代概 ...
- Qt的.pro文件格式解析
Qt的.pro文件格式解析 在Qt中用qmake生成makefile文件,它是由.pro文件生成而来的,.pro文件的具体格式语法如下: 1.注释 .pro文件中注释采用#号,从"#&quo ...