微信号:CocosEngine

介绍:Cocos引擎官方账号,第一时间为您送上引擎动态、精品教程、达人专访等干货,还会定期举办有奖活动喔!

教程:微信小游戏的资源管理

2018-01-02 23:58 Panda

上周微信发布小游戏以来,受到了开发者的热烈反响,这也敦促我们继续努力,跟大家分享小游戏相关的技术细节。我们的开发文档重点在于帮助大家上手小游戏,用 Cocos Creator 发布自己的游戏到小游戏平台上。而在王哲的微信小游戏适配层原理文章中,给大家介绍了微信小游戏环境的基本架构,以及我们的适配原理。

今天我继续接过接力棒,更详细的给大家讲解一下小游戏的环境,我们的资源管理方案,以及为什么在小游戏的环境中催生出这样的方案,用户又可以有哪些定制空间。



1. 小游戏运行环境



借王哲上篇文章中的架构图,可以说很简单明了得展示了微信小游戏的框架。我在这里想说明的最重要一点是:这个架构中,是不存在浏览器的。原因是微信小游戏的运行环境不依赖浏览器实现,而是微信自研的一套 Runtime 环境

这种架构,对于使用过 Cocos Creator 原生平台发布的开发者一定不会陌生,这很像 JSB 的技术架构,其实就是将原生的能力绑定到 JavaScript 接口上。熟悉 Cocos Creator 的开发者估计一下就反应过来了,JSB 环境和浏览器环境有本质的不同,浏览器环境的很多接口其实是无法调用的。所以最近关于很多小游戏的新闻中提到的,微信支持 HTMl5 游戏的说法,严格来说是不正确的,那么这种说法的原因和来历又是什么呢?我们这就来解答。

事实上,微信小游戏环境的确是为了 HTML5 游戏开发者所打造的。在目前的微信小游戏环境中,跟游戏相关性最大的就是渲染接口的绑定,微信为了最大幅度降低 HTML5 游戏开发者的入门门槛和移植成本,小游戏基本支持了 Canvas 2D 和 WebGL 1.0 所有的属性和方法。除了渲染接口以外,其他接口的支持就比较有限了,我们再来看一下微信官方文档中对小游戏运行环境的描述:

你只能使用 JavaScript 来编写小游戏。小游戏的运行环境是一个 绑定了一些方法的 JavaScript VM。不同于浏览器,这个运行环境没有 BOM 和 DOM API,只有 wx API。


所以除了渲染 API 与浏览器同步以外,微信小游戏环境中的其他微信 API 和浏览器并不完全一样,举个例子,在浏览器中加载一个文件,用到的是 XMLHttpRequest,而在微信小游戏中,需要用下面这样的代码来下载文件:


wx.downloadFile({

    url: remoteUrl,

    success: function(res) {

        if (res.tempFilePath) {

            console.log('Downloaded file: ' + res.tempFilePath);

        } else if (res.statusCode === 404) {

            console.warn("Download file failed: " + remoteUrl);

        }

    },

    fail: function (res) {

        console.warn("Download file failed: " + remoteUrl);

    }

});


这些浏览器和微信小游戏环境的差异,我们是不希望用户感知到的,所以接下来将介绍如何适配这些差异。




2. WeApp Adapter


非常幸运的是,微信团队在目前阶段,提供了一个浏览器接口适配脚本,它主要封装了浏览器中最常用的一些 DOM API,比如 document,Image 对象,可以说帮我们省了非常多的工作。然而这还远远不够,为了让 Cocos Creator 中开发的游戏可以无缝发布到小游戏平台,我们帮助开发者做了其他的适配工作:

  1. 资源加载适配

  2. 事件处理适配

  3. 音频播放适配

  4. 窗口适配

  5. 输入框适配

  6. 添加 DOM Parser API


包含所有这些适配代码的 Cocos Creator v1.8 版本足以支撑微信小游戏的绝大多数开发需求了。



3. 小游戏资源加载上与浏览器的差异


除了 API 级别的差异以外,小游戏环境和浏览器环境的另一大差异就是资源加载了,下图是浏览器和小游戏中加载首场景的简要流程:



最大的差异就是,浏览器始终是按需加载,执行到加载的标签或者脚本,才会去作出网络请求加载内容,而在小游戏中,会首先下载你提交的完整游戏包,再运行 game.js 来启动游戏。所谓完整游戏包,也就是开发者在微信开发者工具中所导入的资源,不管你是否需要这些资源,在玩家打开你的小游戏时,都会被完整下载。所以为了首场景加载的体验,我们应该尽可能减小自己的小游戏包体,将可以按需加载的资源,放在远程服务器上,用脚本进行加载。微信团队也考虑到了首场景加载体验,所以将小游戏包体限制在了 4mb。下面是具体的小游戏包体方面的限制:

  1. 小游戏的包内体积不能够超过 4mb,包含所有代码和资源,额外的资源必须通过网络请求下载;

  2. 对于小游戏包内资源,小游戏环境内并不是按需加载的,而是一次性加载所有包内资源,然后再启动页面;

  3. 不可以从远程服务器下载脚本文件。


基于这些限制,我们给出的建议就是,将所有引擎和游戏脚本,放在小游戏包内,同时可以将首场景资源或者预加载场景资源放在包内。其他资源都应该放在远程服务器上。

资源加载上的第二点差异就是:对于从远程服务器下载的文件,小游戏环境没有浏览器的缓存以及过期更新机制。

众所周知,浏览器对于用户已经访问过的资源,会进行缓存,再次访问时,会优先从缓存获取,而不是发送请求给服务端,这样可以尽可能减少网络使用,优化页面响应速度。微信小游戏环境所提供的接口则是更为基础的文件系统接口:

  • wx.downloadFile:下载文件到缓存文件

  • wx.saveFile:保存缓存文件

  • FileSystemManager.access:判断文件/目录是否存在

  • FileSystemManager.readFile:读取本地文件内容

  • FileSystemManager.unlink:删除文件


基于以上接口来实现浏览器的缓存方案当然是可行的,但是对于普通开发者来说,太过于繁琐,所以我们为开发者提供了更完整的资源管理方案。




4. Cocos Creator 的资源管理方案


首先,微信内将小游戏的文件存储空间按照用户和游戏来划分:


上面的文件系统接口,都是在这个文件沙盒环境中执行的,所有的文件目录也是相对于沙盒环境的,所以我们不用担心不同小游戏或者不同用户之间的文件冲突。

在这个前提之下,Cocos Creator 打包的小游戏版本中我们提供了一个 wxDownloader 对象,用户可以给它设置 REMOTE_SERVER_ROOT 属性。而资源的加载流程如下:

  1. 检查资源是否在小游戏包内

  2. 不存在则查询本地缓存资源

  3. 如果没有缓存就从远程服务器下载

  4. 下载后保存到小游戏应用缓存内供再次访问时使用(按照资源相对路径保存)


只要用户保证 REMOTE_SERVER_ROOT 路径下的资源相对路径与 Cocos Creator 发布的资源相对路径一致,那么再次访问同一个资源时,就会在小游戏的文件沙盒环境中找到对应的文件。这样就足够支撑游戏资源的加载和缓存需求了。

那么我们如何做到资源的更新呢?假设服务端资源内容更新了,而 url 没有变化,那么我们还是会优先使用缓存中的资源,岂不是就没有得到更新?的确如此,那么我们解决问题的思路,并不是从资源文件内容是否变化来判断,而是一旦内容变化就修改文件的 url。这点就依赖于 Cocos Creator 打包时的 md5Cache 功能,这个功能会在打包时给所有资源文件的文件名附加 md5 后缀,比如 example.png 变成 example.23j8s1.png,一旦文件内容变化,它的 md5 后缀自然会发生变化。而所有资源文件的相对路径,实际上是在运行时由 AssetLibrary 从 settings.js 中解析出来的。

所以开发者只要更新了新的小游戏包,包含最新版本的 settings.js,那么所有资源的路径就得到了更新,自然会从服务端请求最新版本的资源。由此还可引申出多版本共存的方案,就是不同版本的游戏,指向不同的 REMOTE_SERVER_ROOT 服务器路径,可以保障不同版本都可以访问,并且不会出现资源的冲突或缺失。

至此,Cocos Creator 对小游戏资源管理中,远程资源加载和更新就解释清楚了,虽然我们不希望用户感知到浏览器和小游戏环境的差异,不可否认的是,资源管理方面,用户仍然需要了解更多的细节,才能够更好保障自己的小游戏所带来的用户体验。



5. 定制资源加载方案


我们认为目前的资源加载方案已经比较强大了,不过如果用户依然有自己的定制需求,完全可以通过理解、定制小游戏发布包的 libs/wx-downloader.js 脚本,来满足自己更深入的需求,也欢迎大家发帖到论坛和我们讨论。




6. Q&A


- 如何做到资源加密?


目前 Cocos Creator 打包过程中,如果不勾选 debug 模式,会自动将 JS 脚本混淆,但是并不支持资源的加密。同时,脚本会保存在微信小游戏的文件沙盒环境中,常规的方式并无法获得其中的内容,所以相对来说比浏览器安全许多。

如果实在需要加密,理论上纯 JS 实现的解密库是可以被用于微信小游戏环境的,开发者也可以通过定制 wxDownloader 实现,来完成资源的解密,不过这项功能目前引擎并没有覆盖。

- 微信小游戏环境中还需要微信 JS-SDK 吗?


微信小游戏环境包含完整的微信 API,不需要任何额外的 SDK 支持。

- Cocos Creator v1.8 版本发布 Web 版本并接入微信 JS-SDK 会导致错误怎么办?


这个问题我们会在 v1.8.1 中修复,目前开发者可以自己尝试将 JS-SDK 的加载时机延后到引擎加载完毕,比如:

cc.game.on(cc.game.EVENT_GAME_INITED, function () {

   // 加载微信 JS-SDK

});


- 提示 "未找到入口 app.json" 怎么办?


在上一次 Q&A 中已经解答过这个问题,不过由于困扰的用户比较多,这里再重申一次,目前微信公众平台并没有开放游戏类目的申请权限,所以大家只能通过微信开发者工具中体验小游戏的方式来测试小游戏运行环境(或者使用我们的神秘 appid:wx6ac3f5090a6b99c5)。同时,请保障开发者工具详情页面中选择的库版本是 game。

至于微信何时会开放游戏类目的申请权限,我们在 1 月 2 日得到的答复仍然是:"尚未开放,敬请期待"

- 找不到 "不检验安全域名、TLS 版本以及 HTTPS 证书" 选项怎么办?


当使用体验小游戏的方式来测试时,在开发者工具详情页面中,会找不到 "不检验安全域名、TLS 版本以及 HTTPS 证书" 选项,这是开发者工具的 bug,我们已经反馈给微信团队,目前你可以在 project.config.json 中手动设置 urlCheck 为 false。

- 第三方库(SocketIO,Proto Buffer)可以在微信小游戏环境中使用吗?


目前部分第三方库已经发现有很多不兼容小游戏环境了,这里可以分享一个判断原则,如果是纯 JS 库,那么是没问题的,但是如果第三方库使用到了 DOM API,多半是无法支持。具体到最常用的 SocketIO,protobuf.js,我们引擎自带的 SocketIO 使用的是 global 作为全局 root 对象名,需要改为 window,这个问题在 v1.8.1 会解决。而 protobuf.js 被验证也是会出现问题的,因为它包含了加载的逻辑,这部分逻辑需要适配到微信小游戏的 API 才可以使用,社区中据说已经有大神在研究,希望很快就会有教程分享。




好啦,今天就先写到这儿。有更多关于小游戏的问题,欢迎到 cocos 官方论坛 forum.cocos.com 参与讨论,或者在公众号里留言,告诉我们你想知道的各种技术问题。请持续关注 cocos 微信公众号,我们将陆续推送有价值的技术文章,帮助大家更好地开发和适配微信小游戏。

 
COCOS 更多文章 元旦娱乐:跳一跳秘籍传授,轻松过 4000 分 微信小游戏适配层原理 & FAQ 微信小游戏开启!你准备好了没? 「技术分享」iPhone X 快速适配,快得让你出乎意料 辟谣:苹果禁止用 Xamarin, PhonGap, Appcelerator 等开发应
猜您喜欢 头条丨被“黑化”后的机器学习 真的会令人害怕吗? 从 Spring Cloud 开始,聊聊微服务架构实践之路 科学上网:Surge.conf for Geeks 程序员需要知道的SSD基本原理 企业软件,路在何方?