微信小游戏平台上对首包的的限制是4M,超出限制之后可以采取什么样的措施呢?异名做了一下盘算,大概可以有以下操作
挤牙膏式瘦身
如果我们能够在各种常规的瘦身手段下就可以把超出的容量压缩回到4M以内,那当然是最棒的。这一块能做的无非就是引擎的瘦身和资源的瘦身,而资源无外乎是图片,音频,字体等。
引擎瘦身
首先是引擎代码本身,在开发阶段我们的引擎默认是所有模块都包含进去的,但是在打包阶段,有一些无用的代码模块我们就可以在项目-项目设置-模块设置
中剔除掉,比如一个普通的2D游戏,可能就没有使用到3D模块、物理模块、EditBox
等等,我们最好根据实际的项目的需要勾选自己需要打包的模块,根据异名自己的经验,大部分情况下做了引擎瘦身和没做引擎瘦身的前后做对比,瘦身之后可能至少会帮你省掉你几百k的大小。其中有些功能模块,它的名字不是很直观,你可能不知道自己有没有用到,那就不要勾选。经常会有新手遇到,为什么打包前,在预览模式下项目跑得好好的,但是打包之后项目功能就不正常了,出现这种情况其实很大概率就是你的模块漏勾了,回去校对一下重新打包就可以了。
资源瘦身
资源无外乎是图片,音频,字体。如果是寻常的web项目我们其实有很常用的几个构建工具,像gulp/grunt/webpack
等等,引用相关的压缩库,然后执行构建命令就可以了,但是异名觉得还是没有引入构建工具的必要,因为代码压缩和名字hash引擎已经自身支持了,那音频和字体其实在我们使用之前只要使用工具一次性压缩就可以了,而图片则因为数量太多以及会涉及到自动合图,所以需要在构建之后重新压缩一遍,但是我个人会比较倾向于依赖引擎自身提供的插件机制,毕竟使用了构建工具之后起码还得去npm install
一下,还要去设置每个包自身的一些配置,然后项目build完之后还得去敲个命令,整个一套走下来,其实效率还是不够,而且针对图片压缩,社区内其实已经有能够直接就开箱即用的相关插件,像pngquant
我就用挺顺手的,而且在它的基础上也可以添加一些自己的发布流程进去,比如我就把文件夹改名放到里面,后续的项目直接拷贝过去使用就可以了。
pngquant_customizing
音频这块我建议还是使用第三方的工具吧,我自己习惯使用ffmpeg
。如果有用到其他字体的话,一款普通的中文字体大大几十M,但是我们使用字可能就是那么几个,所以字体提取也很有必要,其实社区内有收费的插件,但是目前中文字体提取库无非就是Fontmin
或者字蛛,它们都可以可以通过终端命令或者客户端和web端去提取所需的字体,异名以前也写过一款小工具,大家需要的话可以去下载来用,地址放在原文链接。
fontmin_tool
资源远程加载
既然本地放不下了,那就把资源放在远端吧。这块引擎的支持也很好,在打包构建的时候填写远程服务器地址,然后把打包后的res目录存放到服务器下,再删除本地的res文件夹就可以了,运行的时候如果在本地没有这个资源就会去远端获取。但是呢,异名在权衡之后,并不会选择这个方案,首先第一个问题是资源在远端,加载会有网络延迟,这个时候场景是黑屏的,解决这个问题可以做一个简单的初始场景,初始场景的资源还是保留在本地,然后在初始场景预加载真实的游戏场景,等到加载完了之后跳转过去
代码语言:javascript复制cc.director.preloadScene("Game", (completedCount, totalCount) => {
// 在这里处理加载进度
console.log(completedCount, totalCount);
}, (error, asset) => {
if (error) {
cc.error(error);
return;
}
cc.director.loadScene("Game")
});
但是这里的骚操作就是你得在res文件夹里面挑选你的首屏资源,面对一堆嵌套的文件和无规则的文件夹名称,那是多大的效率浪费呀,为了提高效率,异名看到社区内看到有人专门写个Python
脚本(怎么感觉发力点选错了呢...),当把资源挑选完毕之后,还得把cdn上的res文件夹删掉,然后重传,那这个发版过程也未免太过于太琐碎了。还有就是网络请求多了,万一遇到个网络不好报个timeout
呀,或者资源更新但是你的cdn节点还没同步过来,然报个notFound
呀什么的,那也得做个异常处理是吧。
resource_error
除了上面说的,异名觉得最关键的还有费用问题,流量都是钱啊,明明微信总包大小有8M,有多少小游戏经过合理的瘦身之后总包大小还能超过8M呢?而且微信针对网络资源的还有一套自己的缓存管理机制,有限的缓存空间满了之后,还要自己去做缓存清理,而且很重要的是微信会在小游戏退出之后自动清理所有临时文件,所以下次再次运行小游戏时,这些资源又会再度下载,然后一直循环往复此过程,几乎每次打开都会重新去拉取,cdn的流量就这么被挥霍掉了。
cdn_waste
当然每种手段都有每种手段的应用场景,异名在社区内还看到有同学利用微信的文件系统去拉取zip资源,然后通过unzip命令去解压的,如果你的游戏资源确实很多很大,那也难以避免的需要使用远程资源,具体场景还是得合理分析才行。
分包
引擎对分包的支持真的非常好啦,对应的文件夹中打个勾就行了。异名的做法其实是多加了一个loading场景,然后把主场景的资源都放在分包里面,在loading场景中通过loadSubpackage
监听下载分包,下载完成后再跳转主场景就可以了。和资源远程加载相比,整个配置步骤清晰明了,发版过程简单流畅,而且省了你的cdn流量,同时微信自身还会对代码包进行主动缓存,一次下载之后就会缓存下来方便下次使用。异名把两者一对比,觉得是分包那是真的香啊~
cc.loader.downloader.loadSubpackage("Game", progressInfo => {
// 在这里处理加载进度
console.log(progressInfo.progress);
}, error => {
if (error) {
cc.error(error);
return;
}
cc.director.loadScene("Game")
});
有几个小点还是需要注意一下:
- 老版本兼容:由微信后台编译来处理旧版本客户端的兼容,后台会编译两份代码包,一份是分包后代码,另外一份是整包的兼容代码。对于老客户端,会去下载整包代码启动
- 2.1.0 以下版本基础库不存在
wx.loadSubpackage
方法,需要通过require来加载(可以在后台屏蔽以下的用户) - 微信 6.6.7 以下客户端开发版/体验版因历史兼容问题无法打开分包小游戏,正式包可以
总结
说这么多,总结下来就是,如果你的代码包超过4M,请先进行各种压缩,如果确实已经是极限压缩了,那使用分包会比远程资源相对来说更加成本更低也更合理。另外异名并不建议子域使用cocos构建,因为确实构建之后又多了一个引擎,首包确实很难控制下来,好的选择是使用canvas的api去绘制或者使用一个简单的模板渲染引擎,当然,这就是另外一个话题了
我是异名,你的阅读是我的动力。