- getSavedFileList返回fileList为空
1、在手机上调试,调用 wx.getFileSystemManager().saveFileSync 保存图片失败,才发现我存储了过多的本地图片,超过了10M。 [图片] 2、为了解决该问题,我试着去获取已经保存过的图片地址列表,但是fileList里面是个空数组。截图如下: [图片] 3、本来如果能获取到已存储的图片地址列表,可以调用unlinkSync接口删除;但是目前我不清楚我之前保存了哪些图片,所以该问题就卡住了。 [图片]
2019-03-15 - android端使用astc无法显示
我们通过调用gl.getExtension('WEBGL_compressed_texture_astc'),发现有所返回[图片],但是在使用后,astc无法显示,在ios上使用astc是正常的,请问下是android不支持astc吗?
2021-11-18 - 调用FileSystemManager.copyFile()接口回调fail
- 当前 Bug 的表现(可附上截图) 调用FileSystemManager.copyFile()保存临时文件时,提示空间不足。但是调用FileSystemManager.stat()和FileSystemManager.getSavedFileList()检查根目录状态,发现其中都是没有文件的,请问这个问题怎么解决? [图片] - 预期表现 - 复现路径 - 提供一个最简复现 Demo
2019-05-21 - 微信小游戏的启动性能优化之首屏渲染
前言 微信小游戏云测试服务的开放之后,越来越多的开发者使用该功能测试自己的小游戏的性能。但是大部分小游戏的测试结果显示,启动性能得分很低,远远达不到80分的标准线,甚至难以达到60分。 [图片] 根据微信小游戏文档中的启动优化最佳实践,优化思路一共有6种: 精简首包资源 分包加载 引擎插件 预下载能力 降低首屏渲染资源 尽快渲染。 常规的优化思路往往是两步: 拆分代码包,精简首包资源,使得首包只存首屏图片和一个加载进度条及相关代码; 使用分包加载。 根据小游戏的启动时序,会发现,降低代码包资源会减少了代码包下载,以及在某种程度下降低JS注入耗时。 [图片] 然而,即使启动优化到这一步,很多小游戏依旧得不到理想的分数。因为使用引擎开发的小游戏,即便只留首包必要资源,也会保留引擎代码,这无非会增加很长时间的JS注入耗时,以及首屏渲染耗时也未得到优化。此时很多开发者已经非常苦恼:我该如何优化呐? 自然而然,解决思路无非是,1. 降低注入代码的大小来减少JS注入耗时; 2. 简化首屏渲染逻辑,比如不依赖第三方引擎进行轻量渲染。但是,怎么做呐? 本文,将结合上面的两个解决思路,提供一套不依赖引擎(WebGL/Canvas2D直接渲染首屏)的小游戏首包加载套路,即减少了引擎代码注入耗时,又避免了第三方引擎的重度渲染。该方式可以直接套用,使用后的小游戏的启动性能在云测试报告下的启动性能得分能达到90及以上。 背景 目前微信官方文档、微信小游戏社区和各个引擎社区已经有很多篇关于启动优化的文章。除了微信官方文档,在微信小游戏社区和cocos 社区下有两篇非常优秀的使用WebGL渲染首屏的文章: 小游戏首屏启动优化 Cocos Creator 微信小游戏平台启动与包体优化(首屏渲染耗时降低 50%) 尤其是第二篇,很多开发者都查资料时查到这一篇文章,按照这篇文章的逻辑来优化小游戏能够达到很理想的效果,本文的思路也是基于该文章之上进一步优化。这两篇文章均是直接使用WebGl渲染首屏,能够达到很理想的效果。强烈先去看一眼这两篇文章及下面的评论,基本上遇到的所有问题都有解答。 但是二者有着各自的缺陷: 第一篇文章简练地介绍了优化思路,但是直接使用的话需要理解WebGL的逻辑并进行改造,存在难度; 第二篇文章是一片很优秀的文章,大家可以先学习一下。该文章中的代码虽然可以直接使用套用,但是代码逻辑和gl渲染的使用方式存在一定的错误,比如重复创建图片,未使用rAF渲染等,这些错误会导致微信客户端统计启动耗时出现异常。然而,因为对gl改写的难度比较大,所以,本文基于第二篇文章中的WebGL渲染首屏的代码进行了改造,附上了正确的使用方式,并额外新增了一份使用Canvas2D渲染首屏的代码。 代码片段 话不多说,附上代码片段: 1. WebGL渲染 webGL代码理解起来还是有难度的,所以代码中的 [代码]webgl_first_render.js[代码]可以直接使用,使用方式可以参考[代码]game.js[代码]。这段代码解决了文章二中的云测启动耗时统计错误、启动黑屏、横屏渲染错误、内存泄漏、屏幕闪烁等异常情况。 代码片段如下: https://developers.weixin.qq.com/s/tknkPjmr7Glg 2. Canvas2D渲染 Canvas2D渲染使用CanvasRenderingContext2D对象 直接渲染。实现上很简单,改造起来也很容易。其实现逻辑是和webgl是一样的。 代码片段如下: https://developers.weixin.qq.com/s/QWno6jmW7Ylx
2020-10-23 - 微信小程序如何处理发版本之前的本地缓存
微信小程序如何处理发版本之前的本地缓存,实际开发中,回遇到比如用户搜索的关键字存本地的操作,但是如果接口调整了,返回的字段发生了变更.那么需要在发布新版本后,处理一下用户之前的本地缓存. 解决方案一: 在版本更新的时候,处理清除缓存操作. (实操失败,也算一种思路,可以试试) onLaunch: function() { // #ifdef MP this.mpUpdate() // #endif } methods: { mpUpdate() { const updateManager = uni.getUpdateManager() // 小程序版本更新管理器 updateManager.onCheckForUpdate(res => { // 检测新版本后的回调 if(res.hasUpdate) { // 如果有新版本提醒并进行强制升级 uni.showModal({ content: '更新到最新版本', showCancel: false, confirmText: '确定', success: res => { if (res.confirm) { updateManager.onUpdateReady(res => { // 新版本下载完成的回调 uni.removeStorageSync('search-history')// 处理清除缓存操作; updateManager.applyUpdate() // 强制当前小程序应用上新版本并重启 }) updateManager.onUpdateFailed(res => { // 新版本下载失败的回调 // 新版本下载失败,提示用户删除后通过冷启动重新打开 uni.showModal({ content: '下载失败,请删除当前小程序后重新打开', showCancel: false, confirmText: '知道了' }) }) } } }) } }) } } 解决方案二: 本地存储版本号, 然后更新后得到最新的版本号,两个版本号不等,然后处理逻辑 文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/account-info/wx.getAccountInfoSync.html [图片] onShow(){ let versionNum = uni.getStorageSync('version') || ''; if(!versionNum){ uni.removeStorageSync('search-history') } let accountInfo = wx.getAccountInfoSync(); let version = accountInfo.miniProgram.version; uni.setStorageSync("version", version); this.initHistory(); // 初始化搜索历史记录 }, 小程序内的缓存,首页调用wx.clearStorage 可以清掉。 旧的版本可以用UpdateManager对象来管理更新 https://developers.weixin.qq.com/minigame/dev/api/base/update/UpdateManager.html [图片] [图片]
2022-12-05 - 微信小程序使用自定义目录(文件路径)进行下载/保存 案例(fail permission denied 解决方案)
场景描述 最近项目中有一个需要把网络文件下载下来保存到本地,然后对下载的文件进行读取,待文件不再使用后把文件进行删除的需求。当然也类似的需求还有很多,比如把小程序中的临时图片/文件永久保存下来等等,都是对文件操作的典型场景。 常见问题 在以上场景的实现过程中可能会遇到各式各样的问题,以下是比较常见的几个: 不清楚文件应该保存到哪个目录下。 fail permission denied 文件权限问题。 使用同步函数不清楚怎么获取执行结果。 API提炼 提到文件操作我们会自然而然地想到了API中的FileSystemManager相关的API,我这里用到的函数有以下几个: 下载函数 wx.downloadFile(Object object) 异步函数: FileSystemManager.access(Object object) FileSystemManager.mkdir(Object object) 同步函数: FileSystemManager.accessSync(string path) FileSystemManager.mkdirSync(string dirPath, boolean recursive) 我对同样的业务逻辑分别分别尝试了异步和同步的两种不同的方案,下面我们用一个最简单的下载保存到本地的案例来切入正题。 案例实践 一:获取正确的文件目录路径 当然在保存文件之前我们先要解决一个小问题,那就是我们要保存到哪里?也就是我们自定义的目录。这里我们简单命名其为 [代码]//自定义缓存文件根路径 var rootPath = "......"; [代码] (当然你也可以命名成其他名字) 变量名字可以随便写,不过自定义路径可不能随便写,也不可以在下载的时候直接给一个path路径,否者就会抛出没有权限或找不到文件的异常。所以开发者并不是可以随意的决定自定义文件的路径,这里就不卖关子了,小程序API中有一个很容易被忽略的API, wx.env.USER_DATA_PATH是专门获取文件系统中的用户目录路径的常量值。 这就是我们在小程序中合法的可操作文件的根目录路径: [代码]rootPath = wx.env.USER_DATA_PATH; [代码] 好了到目前为止我们已经知道了我们该往里存储文件了。 定义一下我们下载文件的缓存目录 [代码]var cachePath = rootPath+"/cache"; [代码] 也就是说之后我们下载的文件都会保存到 /cache 目录下,我们在之后的代码中用到的目录路径均为此路径。 二:异步函数实现方案 我们先来用异步函数来实现一下下载保存的流程。 1 下载文件之前我们首先要判断当前目录是否存在,如果目录不存在我们就直接下载文件到该目录下就会抛出 fail permission denied [图片] 这是判断目录存在的代码 [代码] access() { return new Promise(function(resolve, reject) { let fm = wx.getFileSystemManager(); fm.access({ path: cachePath, success: function(res) { resolve(); }, fail: function(err) { resolve(err); } }); }); }, [代码] 2 如果目录真实存在那我们当然可以直接使用,如果目录不存在则需要开发者自己创建目录。 [代码] mkdir(){ return new Promise(function(resolve, reject) { let fm = wx.getFileSystemManager(); fm.mkdir({ dirPath: cachePath, recursive: true, success: function(res) { resolve(); }, fail: function(err) { resolve(err); } }); }); }, [代码] 代码执行完之后我可以验证一下目录是否如我们所愿被创建出来。 开发工具右上角的详情–>基本信息–>文件系统–>当前小程序文件系统根目录 [图片] 点击usr文件夹进入根目录 [图片] 执行完上面代码之后我们可以看一下 cache 文件夹确实已经存在了 [图片] 3 目录也存在了,万事具备只欠下载了 [代码] downloadFile() { let fileUrl = 'https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg'; wx.downloadFile({ url: fileUrl, filePath: cachePath + '/temp.png', success: function(res) { console.log('downloadFile success', res); }, fail: function(err) { console.log('downloadFile fail', err); } }); }, [代码] 那执行完下载的代码之后我们再来看看cache目录 [图片] 这就是我们刚刚下载的图片。 ok,异步的整个下载和文件创建流程就走完了。接下来我们来瞅瞅同步流程中有哪些需要我们注意的。 三: 同步方案 同步方案和异步方案的流程大体一致,都是先判断文件目录是否存在,若不存在则创建目录,存在则执行下载逻辑。 使用同步函数需要特别注意的是怎么去判断函数的执行结果,由于 FileSystemManager.accessSync(string path) FileSystemManager.mkdirSync(string dirPath, boolean recursive) 这两个同步函数没有直接给出任何的返回结果。那我们怎么知道目录是否存在、目录是否被创建成功了呢? 这里我们需要剑走偏锋一下,即利用同步函数抛出的异常来判断结果。 我们直接来看代码 [代码] accessSync() { return new Promise(function(resolve, reject) { let fm = wx.getFileSystemManager(); try { fm.accessSync(cachePath); resolve(); } catch (err) { resolve(err); } }); }, mkdirSync() { return new Promise(function(resolve, reject) { let fm = wx.getFileSystemManager(); try { fm.mkdirSync(cachePath, true); resolve(); } catch (err) { resolve(err); } }); }, [代码] 可以看到我们的代码中多了 try catch 的代码结构,因为同步方法中没有直接返回给我们可用的信息,那我们可以认为同步函数正常执行完的结果为true或success,而进入 catch 后则结果为false或fail亦或根据具体异常具体处理。我们利用同步函数来走一遍下载保存的流程。 [代码] // 同步函数流程 this.accessSync().then(function (err) { if (err) { return that.mkdirSync(); } }).then(function (err) { if (!err) { that.downloadFile() } }); [代码] 可以看到我们利用同步函数下载的图片。 [图片] 总结时刻 我们分别使用异步和同步函数完成了目录的创建和文件的下载等流程。在这个过程中我们特别需要注意几点: 操作文件的根目录是以 wx.env.USER_DATA_PATH 开头的。 使用自定义目录时一定主要不可直接使用,需要增加 判断目录存在、创建目录 两个步骤。 使用同步函数时的执行结果是通过抓取同步函数抛出的异常来进行判断的。在没有给出直接结果的时候要学会利用异常信息来达到目的。 在创建目录时如果该目录存在同样会抛出异常(fail file already exists),这时按照success逻辑继续往下执行即可。 异步方案中介绍了目录查看的步骤和方法,可自行验证。其中usr目录是开发者自定义目录根节点,tmp目录是小程序默认的缓存根节点。 结尾 叙述若有不对或不严谨之处还请不吝指正。
2019-10-31 - 清除小游戏的资源缓存
- 需求的场景描述(希望解决的问题) 在线上发布新版本后,因为替换了很多新的资源,导致部分用户进入小游戏,提示版本更新,点击确定后,却无法进入。发现是资源有问题,排查过远程资源下载的问题,然后指导用户删除小游戏后,用户就能正常进入,这应该是上一次资源缓存导致的问题。出现这样的问题,是不是说明,在小游戏版本更新重启的时候,并没有及时得清除旧缓存呢?虽然让用户删除后,就能暂时解决这个问题,但是对于大多数用户来说,都不知道如何才是真正删除小游戏本身,这样会造成很大的用户流失 - 希望提供的能力 希望能够提供删除小游戏缓存的API,不仅仅是因为版本更新,还是对于小游戏50M缓存已满的情况,也需要清除缓存。彼之急切,望回复!!!
2019-01-21 - 白鹭引擎游戏针对v2.32.1基础库资源加载慢临时解决方案指引
基础库v2.32.1发布之后,有部分游戏反馈图片加载变慢很多,经排查是触发了安卓底层setTimeout的时序问题,该问题需要基础库发版本修复,由于涉及到底层改动,灰度节奏会相对慢,遇到问题的游戏建议手动修复下。 目前反馈的游戏主要是白鹭引擎的游戏,游戏方可尝试将资源加载回调的setTimeout去掉来修复,参照下图: [图片] 非白鹭引擎遇到类似问题可以排查是不是有不必要的setTimeout逻辑。 如有问题,可以联系我们的小游戏助手一同排查。 [图片]
2023-06-09