- 体验版小程序解密出来的数据没有昵称和头像,这是是正常的吗?
体验版小程序后台解密出来的数据没有昵称和头像,这是是正常的吗?
2021-04-08 - lookup联表查询,需要分页查询时,如何用简洁的代码获取文档总数count?
在分页查询中,一般是需要返回符合条件的文档总数的,下面的代码是先获取文档总数count,然后获取0-20条数据。这两部分的代码高度重复,如果查询条件复杂的话,更是十分冗长。 // 文档总数量count读取 let queryCount = db.collection('cats-order').aggregate() .match(orderMatch) .project({ shopId: true, customerId: true, status: true, services: true, createTime: true, }) .lookup({ from: 'cats-shop', let : { shopId: '$shopId' }, pipeline: $.pipeline() .match(_.expr($.and([ $.eq(['$_id', '$$shopId']) ]))) .project({ _id: false, shopTitle: '$title' }) .done(), as: 'shops' }) .replaceRoot({ newRoot: $.mergeObjects([$.arrayElemAt(['$shops', 0]), '$$ROOT']) }) .project({ shops: false }) .lookup({ from: 'cats-customer', let: { customerId: '$customerId' }, pipeline: $.pipeline() .match(_.expr($.and([ $.eq(['$_id', '$$customerId']) ]))).project({ _id: false, customerTitle: '$title', customerPhone: '$phone', customerLevel: '$level' }).done(), as: 'customers' }) .replaceRoot({ newRoot: $.mergeObjects([$.arrayElemAt(['$customers', 0]), '$$ROOT']) }) .project({ customers: false }) if (searchWord) { queryCount = queryCount.match(_.or([{ customerTitle: new RegExp(searchWord, 'i') }, { customerPhone: new RegExp(searchWord, 'i') }])) } let countRes = await queryCount.count('total').end() pager.Total = countRes.list[0].total // 分页数据读取 let queryList = db.collection('cats-order').aggregate() .match(orderMatch) .project({ shopId: true, customerId: true, status: true, services: true, createTime: true, }) .lookup({ from: 'cats-department', let : { shopId: '$shopId' }, pipeline: $.pipeline() .match(_.expr($.and([ $.eq(['$_id', '$$shopId']) ]))) .project({ _id: false, shopTitle: '$title' }) .done(), as: 'shops' }) .replaceRoot({ newRoot: $.mergeObjects([$.arrayElemAt(['$shops', 0]), '$$ROOT']) }) .project({ shops: false }) .lookup({ from: 'cats-customer', let: { customerId: '$customerId' }, pipeline: $.pipeline() .match(_.expr($.and([ $.eq(['$_id', '$$customerId']) ]))).project({ _id: false, customerTitle: '$title', customerPhone: '$phone', customerLevel: '$level' }).done(), as: 'customers' }) .replaceRoot({ newRoot: $.mergeObjects([$.arrayElemAt(['$customers', 0]), '$$ROOT']) }) .project({ customers: false }) if (searchWord) { queryList = queryList.match(_.or([{ customerTitle: new RegExp(searchWord, 'i') }, { customerPhone: new RegExp(searchWord, 'i') }])) } let listRes = await queryList.sort({createTime: -1}).skip(pager.Offset).limit(pager.Limit).end() return { data: listRes.list, pager, // 返回{ data, pager: {Offset, Limit, Total }}这样的数据结构,是为了和云数据库的http读取方式统一 errMsg: 'collection.aggregate:ok' }
2021-06-29 - 云开发批量上传图片,上传完图片再上传数据库 [即抄即用,拎包入住]
大家好,又是我拎包哥,今天我们来实现在云开发中批量上传图片。 经过Stephen哥的指正,我改用了Promise.all的方法来达到目的。 Promise.all的作用就是等待所包含的promise函数结束后再执行下一步逻辑,非常方便好用!const db = wx.cloud.database() const test = db.collection('test') Page({ onLoad() { this.imgList = [] wx.chooseImage({ success: (res) => { this.TFP = res.tempFilePaths } }) }, btn() { let promiseMethod = new Array(this.TFP.length) for (let i = 0; i < this.TFP.length; i++) { promiseMethod[i] = wx.cloud.uploadFile({ cloudPath: 'img' + i + '.png', filePath: this.TFP[i] }).then(res => { this.imgList.push(res.fileID) }) } Promise.all([...promiseMethod]).then(() => { test.add({ data: { imgList: this.imgList } }) }) } }) --------------------------------------我是分割线-------------------------------------- async await 要点: ctrl c + ctrl v这里用了await阻塞在wx.cloud.uploadFile前面,避免还没上传完图片就往数据库插入数组。减少了then里的代码,美观逼格高。嘻嘻嘻。await wx.cloud.uploadFile不能放在wx.chooseImage里,如果可以的话,请告诉我怎么做,谢谢!欢迎交流,指出错误,我立刻修改么么哒。 标准版 const db = wx.cloud.database() const test = db.collection('test') Page({ onLoad() { this.imgList = [] wx.chooseImage({ success: (res) => { this.TFP = res.tempFilePaths } }) }, async btn() { this.imgList = [] console.log(this.TFP) for (let i = 0; i < this.TFP.length; i++) { await wx.cloud.uploadFile({ cloudPath: 'img' + i + '.png', filePath: this.TFP[i] }).then(res => { this.imgList.push(res.fileID) }) } test.add({ data: { imgList: this.imgList } }) } }) 新手最爱一锅炖版(不推荐) 为什么不推荐呢,因为选择图片并不意味着要上传图片,用户还没进行最终的确定操作(不过可以用来了解async await)。 onLoad() { this.imgList = [] wx.chooseImage({ success: async res => { this.TFP = res.tempFilePaths for (let i = 0; i < this.TFP.length; i++) { await wx.cloud.uploadFile({ cloudPath: 'img' + i + '.png', filePath: this.TFP[i] }).then(res => { this.imgList.push(res.fileID) }) } test.add({ data: { imgList: this.imgList } }) } }) } [图片] ==========================end==========================
2020-05-17 - wx.uploadFile上传失败?
wx.uploadFile上传视频,经常碰到上传失败: "error":{"errMsg":"uploadFile:fail Write error: ssl=0x72b0093688: I/O error during system call, Software caused connection abort"} 或者 "error":{"errMsg":"uploadFile:fail Read error: ssl=0x6efbcc7d88: I/O error during system call, Software caused connection abort"} 这个问题原因是什么?有什么办法可以解决吗?
2020-11-20 - 两个小程序怎么访问一个云开发环境?
我有两个小程序,appid是不同的 一个商家管理后台的版本 一个用户使用的版本 商家在后台上传数据,用户读取数据 应该是在同一数据库下的,但是实际情况是不同appid对于不同的云开发环境 怎么让他们访问一个同云开发环境?
2020-11-12 - 小程序云数据库中,如何查询出“字段的值的长度为某个数字”的所有数据?
比如 {"name":"啦啦啦啦啦","value":1}, {"name":"好好好","value":2}, {"name":"不不不不不不不不","value":3}, …… 我想查询出name字段的值长度为3的所有记录
2021-02-22 - 如何用lookup一次调用,得到多级关联的数据?
新人接触数据库 (超市) 一级类目集合 xxx : 【 { id:0001,name:水果 },{id:002,name:蔬菜}......】 二级类目集合 yyy : 【 { id:1001,name:'热带水果',category:'0001'},{id:1002,name:'非热带水果',category:'0001'},......】 商品集合 zzz: 【 { id:'3001',name:'香蕉',category:'1001' } , { id:'3002',name:'苹果',category:'1002' }......】 只会通过 db.collection('xxx').aggregate().lookup({ from:'zzz', localField:'_id', foreignField:'category', as:'list' }).end() 得到关联的一层数据。 如何 从 通过 db.collection('xxx') 获得被关联的数据list中的每一项也被关联的数据(即获取多层关联的数据,包含最终的商品数据) 好比得到的数据如下 【 { id:0001,name:水果,list:【 { id:1001,name:'热带水果',category:'0001', list: 【 { id:'3001',name:'香蕉',category:'1001' } , { id:'3002',name:'苹果',category:'1002' } 】 } , .... 】 } ...... 】 求大神指点,如何做?还是说我的数据结构是不对的??
2021-02-16 - 【小程序代码自查】小程序闪退-内存泄露导致
背景用户经常出现闪退的情况,并提示内存不足。根据用户操作场景,猜测页面存在内存泄露。 内存泄露是什么?内存泄露是程序运行过程中产生的内存变量会一直存在,不会被垃圾回收机制检测到,导致一直不会被销毁,内存占用会越来越大。 比如说: 我们在运行小程序的时候会产生一个页面,小程序会给这个页面创建一个实例,当这个页面销毁的时候,这个实例应该会被销毁。 但是如果我们有个定时器(setInterval),定时器里面对这个页面实例存在引用,那这个页面实例就不会被销毁,因为有被用到。 当存在内存泄露的情况,用户长期使用我们的小程序会导致小程序占用的内存越来越大,最后会导致小程序闪退(被微信强制销毁) 排查内存泄露用到的工具-weakSet先简单描述一下weakSet,让大家有个简单的认识,详细需要去看下文档。 weakSet 是一个可以存储唯一变量的集合,和Set不一样的是,weakSet存储的变量都是弱引用,就是不会影响垃圾回收,如果存储的变量被回收了,在这个集合里面就找不到。 所以weakSet不能被遍历,也没有长度的概念。但是我们可以通过控制台打印weakset的指向,知道里面有多少个元素。如下图: [图片] 通过展开,我们可以知道里面是哪个页面的实例,但是我们在控制台展开就意味着我们对这个页面实例存在引用,则无法被垃圾回收。所以在执行垃圾回收之前需要清空控制台的输出。 如何确定页面是否存在内存泄露如果页面存在内存泄露则不会销毁页面实例。我们只需要判断页面实例有没有被销毁即可。 我们在一开始就把页面实例加到weakSet里面,当执行多次跳转页面之后,会存在多个页面实例,最后回到首页,触发小程序的垃圾回收。 如果不存在内存泄露,那weakSet集合里面只会存在两个页面实例(当前页面实例+返回回来的页面实例),比如下图的页面A和页面B。 如果存在内存泄露,那weakSet集合里面会存在多个页面实例(当前页面实例+存在内存泄露的页面实例*n),比如下图的页面A、页面B、页面C和页面D. 具体如下图: [图片] 如何主动触发小程序的垃圾回收小程序没有api可以让我们触发小程序的垃圾回收,我们目前可以通过开发者工具的performance面板或memory的垃圾回收(collect garbage 垃圾桶图标)按钮。 [图片] [图片] 触发垃圾回收之后的结果如图: [图片] 这个需要手动触发才可以,我们在测试的时候需要手动点击,无法自动触发,所以我们想了个方案自动触发垃圾回收。 通过给内存塞很多数据,然后将这些数据标为无用的,当内存达到500m左右小程序就会触发垃圾回收。这个办法会导致我们内存一段时间激增,建议尽量在跳转页面的时候不要开启,只有在最后页面跳转回首页才进行。 // 主动触发垃圾回收 setInterval(()=>{ if(!global.startGC){ return } let a = [] for (let i = 0; i < 10000000; i++) { a.push({ name: "pling", age: Math.random() * 10000 }) } console.log("length", a.length) a = [] }, 3000) 如何定位页面内存泄露的原因内存泄露的情况举例: global.list = [] Page({ // ... onLoad() { // ... 省略其他代码 // 将页面实例挂载到全局对象,如没有清理,则页面实例会一直不被销毁 global.list.push(this) // 存在Interval计时器,则会一直存在对页面实例的引用 setInterval(() => { console.log("test", this.data) }, 5000); // 通过settimeout的循环调用,实现了类似于interval的效果也会导致页面实例不会被销毁 this.testLoop() const that = this function test(){ console.log(that.data) } // 将内部函数挂载到全局变量,则会导致函数的作用域链都会存在引用,不会被销毁 global.logThis = test }, testLoop(){ setTimeout(() => { this.testLoop() }, 10000); } }) 通过上面我们可以知道一般会有上面四种情况导致内存泄露。 将对象挂载到全局对象上,页面写在没有清楚通过暴露内部函数给外部对象,导致存在作用域的引用,页面卸载没有清楚内部函数存在定时执行的函数存在对页面实例的引用,页面销毁没有清除定时器通过延时执行的函数循环调用,并存在对页面实例的引用,页面销毁没有停止调用。第一第二种情况会比较少出现,目前暂时还没考虑如何去排查。 第三第四种都会对页面实例存在调用,所以我们在页面实例销毁之后对页面实例上的属性进行监听,如果一直存在调用则会有问题。 [图片] 具体实现代码: // 检查页面卸载后对页面实例调用 Page({ data: { test: "111" }, onLoad() { global.pageSet.add(this) setInterval(() => { console.log("test", this.__wxExparserNodeId__, this.data.test) }, 5000); }, // .... onUnload(){ console.log("unload"); const that = this // 获得可以枚举的属性列表 const keys = Object.keys(that) // 加入data 因为data 不是可以枚举的属性 keys.push("data") console.log(keys); keys.map(key=>{ // 获得原本的属性描述 const property = Object.getOwnPropertyDescriptor(that, key) // 保留原有的值 const origin = that[key]; // 获得属性的get方法 有可能没有 const getter = property && property.get // 获得属性的set方法 有可能没有 const setter = property && property.set const isFunction = typeof origin === "function" // 如果是function的话 需要绑定this if(isFunction){ origin.bind(that) } const newThis = {} // 拦截属性 Object.defineProperty(that, key, { get: function(){ console.log(`调用了this.${key}的getter`); // 有getter 调用getter if(getter){ return getter.call(that) } return newThis[key] || origin }, set: function(newVal){ console.log(`调用了this.${key}的setter`); if(setter){ return setter.call(that, newVal) } newThis[key] = newVal } }) }) } }) 测试demo我们在自己项目里面测试会比较麻烦,一开始可能会有干扰,所以我这边弄了个代码片段,先校验一下这个方法是否可行,如果可行再加到自己的项目里面。 小程序代码片段
2021-05-12 - 云函数运行的时候为什么占用空间那么大?每调用一次都要使用250M?
就3个云函数没几行代码?为什么调试了一天大概编译60来次吧,就能使用了14G云函数资源,是怎么计算的?是每次每个函数调用的时候使用内存250M吗?但内存会释放的嘛 getdate // 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init({ traceUser: true, env: 'prod-xxxx' }) // 云函数入口函数 exports.main = async (event, context) => { return new Date() } getOpenid // 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init({ traceUser: true, env: 'prod-xxxx' }) // 云函数入口函数 exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, } } questionPay // 云函数入口文件 const cloud = require('wx-server-sdk'); cloud.init({ traceUser: true, env: cloud.DYNAMIC_CURRENT_ENV }); // 云函数入口函数 exports.main = async (event, context) => { const res = await cloud.cloudPay.unifiedOrder({ body: event.body, // 商品描述,必填 details:event.details,//商品详情 outTradeNo: event.goodsnum, // 商户订单号,必填,不能重复 spbillCreateIp: '127.0.0.1', // 终端IP,必填 subMchId: event.subMchId, // 子商户号,微信支付商户号,必填 totalFee:parseInt(event.payVal), // 总金额,必填 envId: prod-xxxx, // 结果通知回调云函数环境,你自己小程序的坏境id functionName: 'wechatpay', // 结果通知回调云函数名,非必填参数,即使为空,也不影响支付,但是官方文档里写的是必填参数,表示已醉 //nonceStr:event.nonceStr,//第三个坑:官方文档中相关云函数代码没有nonceStr和tradeType,测试的时候会报nonceStr不存在的错,翻看文档才发现这个是必填项,直接粘过来以后还需要加上这两个参数 //tradeType:'JSAPI' }); return res; }; [图片] [图片] size很小啊 为什么 云开发控制台显示用了几G [图片]
2020-08-16 - 不知道使用云函数 和 js里面啥区别 ?
更新数据库集合里面数据,现在想问下 使用云函数 和 不使用云函数有啥区别?云函数是不是运行时候增加内存?
2020-06-01 - 云开发 Aggregate返回条数?
云开发 Aggregate返回条数有限制吗?
2020-01-01 - 一眼告诉你什么是订阅消息了,看完就懂订阅消息。
消息通知有两种: 一、A的动作后,发消息给A自己,这种容易解决,不多说明; 二、A动作后,发消息给B(比如管理员、店家、楼主),如何保证B收到消息?这种是本方案要解决的问题。 一张图片一眼告诉你什么是订阅消息,产品经理的设计UI居然让人一眼就知道订阅消息是什么玩意。 [图片] 用户 B (管理员、商家、组长、楼主)在知道订阅数不足后,打开小程序来续订阅数,否则没法收到订阅消息。 [图片] 补充一: 关于勾选按钮,请注意话述是:“总是保持以上选择,不再询问”,而不是:“总是同意接收订阅消息”,不要幻想就成了永久性订阅消息; 相当于你打电话订外卖,对店家说“老样子”,店家只会马上送一次外卖,而不是会以后每天自动给你送外卖了。 勾选和不勾选的区别是什么呢? 区别仅仅是:不勾选时,必须点击订阅10次,弹窗10次;勾选后,仍然必须点击订阅10次,但是不弹窗。无论如何“订阅”这个点击n次的动作少不了。 补充二: 一旦勾选后,就不可逆了,没有任何办法恢复或取消勾选了,除非你小程序MP后台换一次消息模板号(删除模板,重新添加一次)。 补充三: 关于如何保存订阅数。 保存在数据库中,笔者用的是云开发,数据库表user结构如下: { _id:'openid1', nickName:'老张', msg:{ "tempId1":5, "tempId2":7, } } 补充四: 关于如何获取订阅数。两种方式: 一、wx.requestSubscribeMessage的回调success里获取; 二、消息推送机制获取;https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/message-push.html
2022-09-21 - 用云开发数据库实现列表触底自动加载功能丨云开发101
云开发数据库之触底自动加载 在前面的两篇文章中,我们简单的谈了谈云开发数据库与传统数据库的差异,以及云开发数据库中的权限机制,今天我们来分享一些实用的代码,快速帮助大家完成自己的小程序的部分功能。 微信小程序实现触底自动加载 在开发小程序类信息流类型的应用时,我们经常会有一个需求,就是当用户将列表滑动到列表的底部时,自动加载新的数据中,从而实现无限下拉,获得一个更好的体验。 大部分用户在进行传统应用开发时,能够实现类似的功能,但在进行云开发相关的开发时,就迷茫了。在云开发中,同样可以实现类似的功能,这一部分,我们就来看一看这部分的实现细节。 原理说明 在小程序中,触底自动加载的功能是基于页面的 [代码]onReachBottom[代码] 事件完成的,当触发此生命周期函数时,则说明小程序已经滑动到页面的底部,需要进行数据的加载。 在使用云开发进行数据加载时,我们可以通过在数据库查询语句中加入 [代码]skip(20)[代码] 来完成跳过所查询数据的前 20 条,从第 21 条开始查询,这样就得出了第二次加载的数据。 这里的 20 是因为云开发数据库 API 单次只能加载 20 条数据,如果你希望其每次只加载10条,可以在代码中加入一个 [代码]limit(10)[代码] 来实现 因此,如果实现页面的触底自动加载的功能,只需要在页面的 [代码]onReachBottom[代码] 中使用 [代码]skip[代码] 进行数据查询,并将该数据附加到原有的数据中,即可完成数据的触底自动加载功能。 实现代码 首先, 我们需要在 Page 实例中定义 [代码]onReachBottom[代码] 事件,并定义一个 [代码]loadData[代码] 函数,用于数据加载,后续,我们可以在 [代码]onLoad[代码] 和 [代码]onReachBottom[代码] 中调用 [代码]loadData[代码] 函数。 [代码]Page({ data:{ items:[] // 用于放置数据的数组。 }, onLoad:function(opt){ // 页面加载完成后,调用此函数 }, onReachBottom:function(){ // 页面滑动触底后,调用此函数 }, loadData:function(){ // 加载数据所用函数 } }) [代码] 为了确保调用时能够不写重复代码,我们可以在 onLoad 和 onReachBottom 中都调用 loadData 方法,从而减少重复代码量,则我们得到的代码如下。 [代码]Page({ data: { items: [] // 用于放置数据的数组。 }, onLoad: function (opt) { this.loadData() }, onReachBottom: function () { this.loadData }, loadData: function () { // 加载数据所用函数 } }) [代码] 这样,我们就完成了 Page 中的基础代码的编写,接下来我们来编写 loadData 中的代码,实现数据的加载。 对于 loadData 函数,我们需要它首先获取到当前已有数据(默认初始化进入页面时,默认数据为空),然后基于已有数据的长度,进行跳过查询,从而查询当前从未查询的数据。 在获取到新的数据以后,使用 Array 的 [代码]concat[代码] 方法,将新的数据拼接进入到老的数据中,从而获得了一个更大的数组,完成数据的新增。具体代码实例如下: [代码]loadData: function () { let old_data = this.data.items; const db = wx.cloud.database(); db.collection('items').where({ done: false, }).skip(old_data.length).get().then(res => { this.setData({ items:old_data.concat(res.data.data) }) }) } [代码] 最终,我们得到的 Page 实例的代码如下 [代码]Page({ data: { items: [] }, onLoad: function (opt) { this.loadData() }, onReachBottom: function () { this.loadData }, loadData: function () { let old_data = this.data.items; const db = wx.cloud.database(); db.collection('items').where({ done: false, }).skip(this.data.items.length).get().then(res => { this.setData({ items:old_data.concat(res.data.data) }) }) } }) [代码] 在完成了 Page 实例的代码以后,我们需要调整页面结构的代码,从而确保我们的数据在进行循环时,不会因为新增数据导致数据错位。这需要我们使用一个唯一的 Key 作为 [代码]wx:key[代码] 的值,具体的实现代码如下: [代码]<view wx:for="{{items}}" wx:key="_id"> {{item}} </view> [代码] 这段代码实现了使用云开发所自带的 ObjectId 作为 [代码]wx:key[代码] 的的值,从而确保我们的数据更新完成以后,不会出现数据错位的情况。 这样,我们就完成了触底自动加载的功能。 参考文献: 小程序 Page 构造器说明:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html 更多云开发使用技巧及 Serverless 行业动态,扫码关注我们~ [图片]
2019-09-24 - 云开发应该怎么切换正式和测试环境
- 我现在云函数里面已经指定了正式的数据库环境,因为要上线了,肯定要改。。。 [图片] 但是我上线了之后,我在平时的开发中,要怎么切换到测试环境的云开发数据库啊!!! 我总不可能全部改成dev环境的数据库,然后部署上去,这样的话线上就炸了啊!????? - 希望提供的能力 请问现在有方法可以切换云开发的正式和测试环境的数据库吗????? 不然我现在每次调试就会往正式的云数据库插入脏数据,这很难受啊··· 拜托各位开发者看看,谢谢了。 ================================================================= 我看下面有一位评论说云函数不要指定,但是我试了还是不行,我先把截图放上来 云函数 [图片] 往云数据库插入一条数据 然后两个环境的云函数列表,都确认已经部署上去了 [图片] [图片] 在app.js里面初始化 [图片] 最后我点击自定义按钮触发云函数的时候,全部数据只在dev环境产生,在release根本没有。 [图片] [图片]
2019-06-04 - 分片录音的回调参数isLastFrame不正确
- 当前 Bug 的表现(可附上截图) - 预期表现 - 复现路径 - 提供一个最简复现 Demo 小程序录音时,设定frameSize后,在回调函数 recorderManager.onFrameRecorded 接收到的isLastFrame不正确。 即使是最后一个分片返回的也是false 代码片段 [代码]const options = {[代码][代码] [代码][代码]duration: 10000, [代码][代码]// 录音的时长,单位 ms,最大值 600000(10 分钟)[代码][代码] [代码][代码]sampleRate: 16000, [代码][代码]// 采样率[代码][代码] [代码][代码]numberOfChannels: 1, [代码][代码]// 录音通道数[代码][代码] [代码][代码]encodeBitRate: 48000, [代码][代码]// 编码码率[代码][代码] [代码][代码]format: [代码][代码]'mp3'[代码][代码], [代码][代码]// 音频格式[代码][代码] [代码][代码]frameSize: 1 [代码][代码]//200ms的切片大小[代码][代码]}[代码] [代码]recorderManager.onFrameRecorded(res => {[代码][代码] [代码][代码]const {[代码][代码] [代码][代码]frameBuffer,[代码][代码] [代码][代码]isLastFrame[代码][代码] [代码][代码]} = res[代码][代码] [代码][代码]console.log(res)[代码][代码] [代码][代码]ws.sendMessage(api.Frame, {}, {[代码][代码] [代码][代码]seq: seq++,[代码][代码] [代码][代码]isEnd: isLastFrame ? 1 : 0,[代码][代码] [代码][代码]data: wx.arrayBufferToBase64(frameBuffer),[代码][代码] [代码][代码]})[代码] [代码]})[代码] 上面的ws.sendMessage是用websocket送信。
2019-07-09 - 各位保护好代码
微信小游戏可以被反编译的问题怎么解决. 和小程序一样,单机版的小游戏可以被直接反编译,并且上架. 这里给出两个游戏的试玩视频,一个是我的,一个是别人的 引力怪[我的] https://v.youku.com/v_show/id_XMzc0NDE4OTIyMA==.html?spm=a2h3j.8428770.3416059.1 观看密码:123456 无尽黑洞[盗版]试玩视频: https://v.youku.com/v_show/id_XMzc0NDE5MDY1Ng==.html?spm=a2h3j.8428770.3416059.1 观看密码:123456 附上一个横向对比图: [图片] 两次投诉结果: [图片]
2018-07-26 - 希望云开发数据库支持 distinct 去重
- 需求的场景描述(希望解决的问题) 现在只能自己取出所有数据,一条条循环比对才能去重,太过消耗资源浪费时间 - 希望提供的能力 希望云开发数据库支持 distinct 去重
2019-07-07 - 云开发之音频列表播放
说明 音频播放列表中播放云开发中存储的音频文件,可以使用fileid,直接播放。 错误实现方式 在xml文件中添加<audio>组件,src为云存储文件的fileid来实现音频播放,报错Uncaught (in promise) NotSupportedError: The element has no supported sources.,截图如下: [图片] 原因为该组件src只能设置具体地址,该组件无法解析云文件的fileid到详情里的地址。 解决办法:使用wx.createInnerAudioContext()创建内部 audio 上下文 InnerAudioContext 对象,xml无需写<audio>组件,通过innerAudioContext.src设置为获取到的fileid。 遇到的问题:因为切换音频列表中的任意音频播放(当前音频正在播放中),而生成的音频实例只有一个,所以播放暂停等操作都是在同一个音频实例上,导致不暂停当前播放直接播放另一个音频还会继续播放前一段音频。 解决办法:定义一个全局InnerAudioContext 对象,在播放方法中首先销毁掉原来的对象并重新生成一个,之后再设置src并play()。注意:需在可播放状态监听事件里play()。暂停方法中则执行pause()。 完善:这样的话暂停当前选中音频,再重新点击播放会从头开始播放。暂停时设置一个变量preIndex存当前选中index,播放时判断当前选中index是否为preIndex,若不是则代表切换到了另一个音频,销毁当前InnerAudioContext 对象并重新生成一个。否则继续播放这个对象。当播放完时可以添加监听方法,改变播放状态。 部分代码: [代码]var innerAudioContext = wx.createInnerAudioContext(); Page({ data:{ voiceList:[],//音频列表,fileid preIndex:-1,//正在播放中的音频index }, //播放 play: function(e) { var that = this; //获取下一个播放的音频index var index = e.currentTarget.dataset.index; //正在播放的音频 var preIndex = that.data.preIndex; if (index != preIndex) { innerAudioContext.destroy(); innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.src = voiceList[index].fileId; innerAudioContext.onCanplay(function() { innerAudioContext.play(); }) } else { innerAudioContext.play(); } }, //暂停 pause: function() { var that = this; innerAudioContext.pause(); that.setData({ preIndex:that.data.selectIndex }) } }) [代码]
2019-03-07 - 求问,一个关于录音和播放的问题。
使用 wx.getRecorderManager/wx.createInnerAudioContext 来录音和播放,在开发工具上,播放回调回来的录音地址,一直是错误码1004(格式错误)。真机上可以使用,工具上 一直 错误,有人遇到过么?怎么解决?录音能否使用 wx.getBackgroundAudioManager()来播放??
2018-10-29 - createInnerAudioContext 音频无法播放
一、 这是录音的全局唯一变量,开始录音产生的文件是mp3[图片] 上传云开发的服务器,获得了云文件id 直接播放云文件id报错[图片] 触发错误回调 ,pc是可以的[图片] 二、 在pc上无法启动录音,是因为电脑没有麦克风吗?
2019-07-26 - 【安卓】小程序音频播放报10001
在电脑上测试时,日志只看到“播放音频”,没有其它音频播放的相关日志出现,拿耳机听,也没听到声音; 安卓手机验证时,会报10001错误(errCode:10001, errMsg:"errCode:602,err:error,not found param") 样例中用的是本地音频文件,如果是在线音乐是可以播放的。 测试用的机型:一加3T 7.1.1版本系统 [图片] 部分代码: playAudio: function () { console.log('播放音频') var innerAudioContext = wx.createInnerAudioContext() // innerAudioContext.autoplay = true innerAudioContext.src = './audio/v_10.mp3' innerAudioContext.onPlay(() => { console.log('开始播放') }) innerAudioContext.onError((res) => { console.error(res) }) innerAudioContext.play(); }
2018-08-10 - 使用云开发的小程序,上线时不需要配置生产环境吗
小程序使用云开发,还需要有自己的域名和服务器吗? 如果不需要,那应该如何配置小程序的“服务器域名”? 3.如果需要,对服务器环境有什么要求吗,那云开发的意义仅限于开发之中吗?
2019-07-07 - 轻松实现小程序直接上传图片至腾讯云对象存储
概念介绍 对象存储(Cloud Object Storage,COS)是腾讯云提供的一种存储海量文件的分布式存储服务,用户可通过网络随时存储和查看数据。腾讯云 COS 使所有用户都能使用具备高扩展性、低成本、可靠和安全的数据存储服务。 前期准备 登录腾讯云对象存储控制台创建存储桶,获取 Bucket(存储桶名称) 和 Region(地域名称)。 通过管理控制台的 密钥管理 获取您的项目 SecretId 和 SecretKey 下载对象存储SDK,至小程序对象存储gitHub项目目录下载https://github.com/tencentyun/cos-wx-sdk-v5/tree/master/demo/lib下的cos-auth.js文件,添加至项目目录 项目实践 一、引用 [代码]var CosAuth = require('cos-auth');//引入对象存储SDK var config = require('../utils/api.js');//定义了项目的一些配置内容,例如存储桶名称、地区、请求域名等 var stsCache; //存储临时秘钥及秘钥过期时间内容 //定义上传接口 var uploadFile = function(filePath, cb) { // 请求用到的参数 var prefix = 'https://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com/'; // 对更多字符编码的 url encode 格式 var camSafeUrlEncode = function(str) { return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A'); }; // 获取临时密钥 // 全局变量stsCache 存储临时秘钥及过期时间内容 var getCredentials = function(callback) { //判断临时秘钥未过期 if (stsCache && Date.now() / 1000 + 30 < stsCache.expiredTime) { callback(stsCache && stsCache.credentials); return; } //过期,服务器重新请求获取临时秘钥 wx.request({ method: 'GET', url: 'https://baidu.com/Api/Cos/getCosTempKeys', // 服务端签名,参考 server 目录下的两个签名例子 dataType: 'json', success: function(result) { var data = result.data.result; var credentials = data.credentials; if (credentials) { stsCache = data } else { wx.showModal({ title: '临时密钥获取失败', content: JSON.stringify(data), showCancel: false }); } callback(stsCache && stsCache.credentials); }, error: function(err) { wx.showModal({ title: '临时密钥获取失败', content: JSON.stringify(err), showCancel: false }); } }); }; // 计算签名 var getAuthorization = function(options, callback) { getCredentials(function(credentials) { callback({ XCosSecurityToken: credentials.sessionToken, Authorization: CosAuth({ SecretId: credentials.tmpSecretId, SecretKey: credentials.tmpSecretKey, Method: options.Method, Pathname: options.Pathname, }) }); }); }; // 上传文件 var uploadFile = function(filePath, cb) { var Key = filePath.substr(filePath.lastIndexOf('/') + 1); // 这里指定上传的文件名 getAuthorization({ Method: 'POST', Pathname: '/' }, function(AuthData) { var requestTask = wx.uploadFile({ url: prefix, name: 'file', filePath: filePath, formData: { 'key': Key, 'success_action_status': 200, 'Signature': AuthData.Authorization, 'x-cos-security-token': AuthData.XCosSecurityToken, 'Content-Type': '', }, success: function(res) { var url = prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'); if (res.statusCode === 200) { if (cb) { cb(url); } } else { wx.showModal({ title: '上传失败', content: JSON.stringify(res), showCancel: false }); } }, fail: function(res) { wx.showModal({ title: '上传失败', content: JSON.stringify(res), showCancel: false }); } }); requestTask.onProgressUpdate(function(res) { }); }); }; // 触发上传文件方法,按步骤调用执行 uploadFile(filePath, cb); }; module.exports = { uploadFile }; [代码] 2、调用以上SDK实现上传 1、 在需调用的文件,首先引入以上文件 var demoNoSdk = require(‘sdk文件路径’);//引入上述的对象存储SDK文件 2、 获取到上传文件的临时路径(备注:可以是直接调用wx.chooseImag方法获取的临时文件,也可以是调用wx.canvasToTempFilePath将画布导出的临时图片路径等等其他方式获取的到的临时图片文件路径) 这里调用wx. chooseImage为例 [代码]wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: function(res) { //临时文件路径 var tempFilePath= res.tempFilePaths[0]; //定义上传图片成功后的回调函数 var callback = function(url) { //url为上传至对象存储成功后返回的云存储文件路径 //do other something …… }; //调用对象存储SDK,实现文件上传 //传递参数临时文件路径及上传成功后的回调函数,若不需要回调可不传此参数 demoNoSdk.uploadFile(tempFilePath, callback); }, }) [代码] 实现上传的过程如下 获取图片临时文件路径 ->调用SDK的uploadFile方法 ->服务器请求获取请求对象存储功能所需要的临时秘钥(并将秘钥结果及过期时间存储至全局变量,方便后面直接调用已缓存的未过期的临时秘钥即可,无需重复请求服务器获取) ->调用wx.uploadFile接口上传图片 ->上传成功后调用我们自定义的回调函数实现我们自己的业务。 至此,小程序直接上传图片至对象存储完成!
2019-04-27 - 配置业务域名怎么搞都不行
业务域名校验失败,按照自查指引检查都通过,麻烦帮忙看看是什么问题,该如何解决? 校验文件地址:https://hx.peimeizh.com/FGFFHPq34T.txt 校验文件内容:27da457e79eecaeeb1a921209cab0a6d AppID:wx120f5ef2c6ec9942 [图片]
2019-06-29 - 阿里云服务无法校验业务域名的一种解决方式
发生错误场景: [图片] 解决方法:需要服务器名称指示不要打钩(见下图) [图片] 我是阿里云的服务器,目前我以这种方案解决这个问题。。大家可以参考试试
2019-07-04