- [开盖即食]小程序Canvas官方新版API实战
[图片] [图片] 最近本人在开发一个新项目的时候,注意到官方在2.9.0开始支持了一个canvas 2D的新API,同时对webGL上支持也有了很大的改进,相信很多人用canvas的组件做一些分享海报,战绩和新闻帖功能。 [图片] 这里是新的引入方式。 官方文档地址: https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html 那么新的canvas2D API有啥好处呢? 原本的API微信有做一定的修改,现在全面支持源生H5 JS的写法,迁移H5的老代码变成更加容易,学习成本更低 修复了一些诡异的BUG,例如原本在IOS早期版本写法顺序会导致clip()图片裁切失效等~ 性能上的优化和提升,复杂动画上帧数明显 举例写法上的一些改变: 1、设置font的写法: [代码]//原本(传值的写法) ctx.setFontSize(20); ctx.fillText('MINA', 100, 100) ctx.draw() //现在(和源生H5写法一致,赋值) ctx.font = "16px"; ctx.fillStyle = 'blue'; //可以直接写颜色,原本的不支持 //不需要 ctx.draw() [代码] 2、获取并添加图片写法: [代码]//原本 //使用的是 wx.getImageInfo的方法 wx.getImageInfo({ src: mainImg,//服务器返回的图片地址 success: function (res) { console.log(res); ctx.drawImage(res.path, 0, 0); ctx.draw(true); }, fail: function (res) { //失败回调 } }); //现在 //可以直接img.onload调用 const headerImg = canvas.createImage(); headerImg.src = headImage;//微信请求返回头像 headerImg.onload = () => { ctx.save(); ctx.beginPath()//开始创建一个路径 ctx.arc(38, 288, 18, 0, 2 * Math.PI, false)//画一个圆形裁剪区域 ctx.clip()//裁剪 ctx.drawImage(headerImg,0,0); ctx.closePath(); ctx.restore(); } [代码] 3、将canvas生成虚拟地址便于下载(重点): [图片] 由于官方文档没有写清楚,误导了挺多人的。这里canvas对象必须通过选择器获取,并获得对应的node节点。 [代码]async saveImg() { let self = this; //这里是重点 新版本的type 2d 获取方法 const query = wx.createSelectorQuery(); const canvasObj = await new Promise((resolve, reject) => { query.select('#posterCanvas') .fields({ node: true, size: true }) .exec(async (res) => { resolve(res[0].node); }) }); console.log(canvasObj); wx.canvasToTempFilePath({ //fileType: 'jpg', //canvasId: 'posterCanvas', //之前的写法 canvas: canvasObj, //现在的写法 success: (res) => { console.log(res); self.setData({ canClose: true }); //保存图片 wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: function (data) { wx.showToast({ title: '已保存到相册', icon: 'success', duration: 2000 }) // setTimeout(() => { // self.setData({show: false}) // }, 6000); }, fail: function (err) { console.log(err); if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") { console.log("当初用户拒绝,再次发起授权") } else { util.showToast("请截屏保存分享"); } }, complete(res) { wx.hideLoading(); console.log(res); } }) }, fail(res) { console.log(res); } }, this) }, [代码] 分享个canvas海报的代码片段: [图片] 片段名: PoCf4emw7TgE 片段link: https://developers.weixin.qq.com/s/PoCf4emw7TgE [图片] [图片] 总结,相对之前还要看官方文档的canvas自定义API,现在写起来更加的方便,老代码迁移起来得心应手,只要你之前会canvas,那么各种效果和动画,拿来就怼,没什么大问题~ 一些奇怪的问题(注意!!!) canvas 2d 目前(2020年4月3日)还不支持真机调试,会报错!!! IDE工具 1.02.2003190 直接保存新版本canvas的API图片是打不开的,但是直接用手机保存在相册是没问题的,请更新到1.02.2003250 最新版即可解决~ 一些老款手机用新的API保存图片会有报错问题,如华为NOTE10,请更新系统到能支持的最新,且微信也是,即可解决~ 部分Android设备诡异的闪退和报错 [图片] 这种有可能是代码写法的问题,比如: [代码]//缺省写法 会导致部分Android机器 闪退 ctx.font = "bold 16px"; ctx.fillStyle = "#000" //在canvas 2D的写法中,所以写法必须规范且完整 ctx.font = "normal bold 12px sans-serif"; ctx.fillStyle = '#707070'; [代码] 所以在canvas 2D 的环境,所以写法必须原始且规范,不能用缺省写法,不然就会有诡异的闪退/报错。 后续:官方在7.0.13的Android版本已修复。 https://developers.weixin.qq.com/community/develop/doc/00088c13e1437890692afd8d85ec00 看完觉得有帮助记得点个赞哦~ 你的赞是我继续分享的最大动力!^-^
2020-05-09 - 一种小成本的线下定位方案 ---2019腾讯数字文创节小程序开发有感
去年的TGC小程序,我们采用了小成本的智能印章来连接线上线下(点此查看知晓程序的报道),今年,我们利用了成本更低的ibeacon设备,来做室内定位。先放码: [图片] 介绍下今年的TGC小程序 今年的2019腾讯数字文创节(以下简称TGC)的举办地点是在世界最大的单体建筑----成都环球中心里面,整个场馆区域非常大,同时场馆内有很多商区,为了能更加突出打卡TGC的整体性,我们将整个TGC所有的场馆地点设计在一个全场地图上,玩家可以很清楚的看到所有打卡点的分布和场馆的具体位置: [图片] 每年的TGC小程序我们在尝试一些新的技术形式的加入。今年TGC整体升级为腾讯数字文创节,整个活动以展会形式为主,整个TGC共设为值四大展区-----IP主题(该主题展区内有每个游戏ip单独布置的展区)、传统文化、竞技文化和未来探索,相较于去年的形式,今年更加侧重在和传统文化进行集合,所以我们在玩法上还是和去年一样,采用打卡的方式,但是在形式上,则采用了更加适合玩家感受游戏文化和传播内容的拍照打卡。通过打卡得积分、分享打卡照邀请好友点赞得积分和积分抽奖的方式,来带动活动线下的参与以及线上的传播。整体的效果图如下: [图片] 既然是玩家参观TGC场馆打卡得积分,那么如何验证玩家是否在该打卡点内呢? 小程序ibeacon ibeacon简介 ibeacon是2013年苹果提出来的一套可用于室内定位系统的协议,它可以以指定频率广播自身信号,信号本身带有设备的数据帧,只要手机设备支持解析这个数据帧,处于ibeacon信号广播范围的手机设备可以接收到这些数据信息,详细介绍请点击这里。 小程序ibeacon API提供的数据信息包含以下部分: UUID 设备的唯一通用标识符,一般不同的厂商不同的批次,这个编号也不一样,具体是设备厂商自己设置 Major 设备的主ID,这个一般代表设备的型号,同一批次的ibeacon设备,这个编号一般也一样 Minor 设备的次ID,每隔设备的这个编号都不同,一般用来指代唯一性 Accuracy 设备的距离,单位为米 Rssi 接收到的设备信号强度 设备就是联系供应商提供的,价格是45到60左右,成本非常低,就是这个小白盒子: [图片] 首先,因为活动的举办地点是在商场,可以预见的是,商场本身会有些商家会部署ibeacon设备来做活动营销(微信摇一摇),所以如何保证小程序接收到的ibeacon设备信息就一定是我们部署的ibeacon设备发射出来的呢?答案就是通过上面提到的Major。 收到设备后,我们首先设置这一批ibeacon设备的Major为我们特定的数字,在接收到的ibeacon信息后过滤掉不是我们制定Major号的设备信息即可。通过在数据库绑定打卡地点和设备Minor的关系,玩家手机接收到ibeacon设备的信号的时候,就可以通过接收到设备的Minor号判断玩家当前是在哪个体验点。坑爹的是,设备的厂家在出厂这些设备的时候,每个设备的Major和Minor号都是随机,幸好网上有很多ibeacon设备信息查看更改软件,推荐使用 “摇一摇助手”,app store和安卓应用商店都可以下载。 [图片] ibeacon踩坑 1、通常市面上的ibeacon设备是可以设置ibeacon设备的广播频率的,默认一般是500ms。为了提升感应玩家当前所在的地点的精度,我们会去调高ibeacon设备的广播频率。设备的广播频率是可以通过专门的ibeacon设置软件调整(PS:会导致设备更加费电,但是现在的ibeacon设备基本都可以用个好几年,如果不是长期使用的话,可以不care这个),但是小程序ibeacon API读取设备广播信息的频率是系统控制,也就是说,其实我们调整设备的广播频率是起不到作用的,因为最终读取ibeacon的广播信息频率是由系统所决定的,请教过微信的同学,安卓的是500ms,iOS 这边跟着系统走,目前观测是 1秒1次。 [图片] 2、接收ibeacon信息的API需要在wx.startBeaconDiscovery成功的回调中调用才能拿到ibeacon的设备信息。 [代码]wx.startBeaconDiscovery({ uuids: ['B9407F30-F5F8-466E-AFF9-25556B57FE6D'] // ibeacon uuid }).then((res) => { wx.onBeaconUpdate(() => { console.log('onBeaconUpdate') wx.getBeacons().then((res) => { let beacons = res.beacons, len = beacons.length, i = 0, nearbyBeacons = [], if (len === 0) { return } for (; i < len; i++) { if (beacons[i]['major'] !== 700) { continue } else { if (beacons[i]['accuracy'] > 0 && beacons[i]['accuracy'] < 8) { // 读取周围ibeacon设备的精度,可根据现场情况动态调整 nearbyBeacons.push(beacons[i]['minor']) } } } let _nearbyBeaconsResult = that.data.nearbyBeaconsResult if (_nearbyBeaconsResult.length >= 4) { _nearbyBeaconsResult.shift() } _nearbyBeaconsResult.push(nearbyBeacons) that.setData({ nearbyBeaconsResult: _nearbyBeaconsResult }) }) }) }) [代码] 在实际的开发过程中,我们发现,少数ibeacon设备的信息读取到的距离信息(accuracy)会出现负数,这个是因为之前提到的设备的广播频率的原因,如果在小程序内接收到设备的广播信息恰好出现在设备的广播周期之外,那么这个设备的的信息其实算作没读取到。为了规避这个问题,我们设置一个数组,这个数组存储最近4次接收到的ibeacon数据,按照一般ibeacon的广播频率的话,也就是2s的时间内,接收到的ibeacon设备信息。同时,我们在线下会针对体验点的区域的大小的不同,部署不同数量的ibeacon设备,这样可以大大的降低玩家接收不到ibeacon信息的概率。 现场方案执行 最基础的技术方案也想对容易实现一些,但是往年的线下活动的经验告诉我们,问题往往不是出现在实现的技术方面,我们需要考虑的往往是一些非技术侧的问题: 1、现场地形复杂,在什么地方部署ibeacon设备才算合适呢,不同的展区部署多少个点才算合适? 2、ibeacon的信息接收需要依赖蓝牙,玩家的手机因不明原因无法开启蓝牙或蓝牙功能失效了,如何处理? 第一个问题,我们在活动开始的前一个多礼拜,就带着我们做好的小程序测试版本去到了活动举办地成都环球中心进行了测试。 [图片] 实地的测试主要是对每个体验点的区域进行确定,再根据体验点的大小来决定需要放置多少ibeacon设备。 第二点在有了去年的经验,其实处理起来也有成熟的方案可以去执行。TGC的每个线下体验店会有我们Part Time(场馆负责人),还会有全场的巡视人员,我们只需要做一套后备方案,在少数玩家因设备问题无法打卡时,让现场我们的工作人员赋予玩家特殊的权限,可以让玩家不需要因设备的限制进行打卡即可。所以,我们做了一套玩家扫码打卡的后备方案,在活动开始之前,我们给予管理员特殊权限,它们可以在小程序的管理端选择打卡点二维码,玩家扫一扫即可完成定位打卡,当然每个小程序二维码只能够用一次,剩下的工作就是和现场的Part time进行培训。 [图片] 小程序云 这次活动的开发排期十分紧张,后台的开发人力又无法及时跟进项目,所以这次的整个活动的开发我们十分大胆的尝试了小程序云。其实在小程序云内部测试的时候,我们就已经有预研过小程序云。 小程序云提供了云存储、云函数和数据库,提供了较为完整的云端支持,还搭配了一套基础运维体系,开发者无需关心服务器搭建和代码部署。关于一些基础的类似云函数提供了鉴权的内容啥的,这里受限篇幅也就不再阐述,可自行查看开发者文档,这里讲下我在开发过程中的小总结吧。 1、小程序云环境 每个小程序账号开通了小程序云能力后会默认得到一套云开发环境,每个小程序账号最多可以创建两个云开发环境,一个云环境用于开发环境,一个云环境用于线上环境。 小程序端只需要在小程序云初始化函数配置当前运行的环境ID即可: [代码]// app.js App({ ...... globalData: { wxCloudEnv: 'tgc-production-xxxx' // 当前运行环境ID } }) // index.js wx.cloud.init({ env: app.globalData.wxCloudEnv }) [代码] 但是小程序云上,即使云函数当前运行的云环境不一样,也需要在每个云函数上显式的配置当前运行的云环境ID,要不然可能会在线上环境的云函数也会调用到测试环境的数据库和云存储。 现在每个云环境默认是基础的资源配额,可以自行发邮件申请. 2、小程序云的权限控制 小程序云提供的API分为小程序端API和服务端API,顾名思义,一套是在小程序的代码里调用的,一套是在服务端云函数调用的,两套API都可以进行数据库操作、云函数调用和云文件的操作。 [图片] 小程序端的数据库API在添加一条数据库记录的时候,该条数据库记录会默认加上_openid字段,值为该条记录创建者(也就是用户)的openid,而如果是服务端数据库API进行同样的操作就不会带上该字段。小程序云数据库的集合默认的权限都是设置为"仅创建者和管理员可读写",在小程序端如果通过数据库API访问数据库某个集合的数据时,只能访问到用户自己在小程序上调用数据库API创建的数据,写的逻辑也是一样,另外几个权限也是很好理解。小程序云管理后台可以设置数据库的操作权限,不同的用户对数据的读写权限不同,通过这个操作,可以灵活的调整数据库中的数据使用场景。 3、小程序云的局限性 小程序云暂时还不支持数据外部调用,所以,如果运营人员需要有很强的数据配置和数据管理的功能的话,小程序云想对做起来会很吃力(预计是年后会支持,大赞小程序云的团队)。而且,我们暂时还只能使用其提供的几项能力,如果我们想继续扩展我们的应用且需要在服务器上部署一些其他的服务的话,在小程序云上暂时还是做不到的。小程序云的数据库查询支持还是较为基础的,一些例如在关系型数据库常见的连表查询啥的还不支持,所以在做一些复杂的查询的时候,为了效率通常需要再一个数据库集合中增加一些冗余字段。 感觉小程序云还有很大的发展潜力,后续这些功能应该都会逐步的开放出来,相信小程云也会变得越来越强大。 线上结合线下ibeacon的优势 1、统计当前玩家所在的区域,绘制全场的玩家分布热力图,及时做好访问量较低的现场场馆引导。 [图片] 2、成本极低。成都环球中心在周末高峰时段是可以达到5~6w的人流量,在那么大的人流量下,我们也只需要在现场近20个体验点布置将近100个设备,就能覆盖我们全部的打卡体验点,按照每个设备本身价格近45元算,整个总成本可想而知。而且设备本身可以回收继续再利用,技术方案也是可以继续复用。 总结 今年是参与TGC小程序开发的第二年了,这种线下的项目最大的挑战在于需要对接的需求方非常之多,涉及到线上、线下、供应商等等多个角色。在开发周期如此紧张的情况下又需要同时兼顾前后端开发情况,对于个人来说是个非常大的挑战,但也是一个非常好的锻炼机会。有了去年TGC小程序的参与经验,今年在线下的部分也较为顺利的执行下去,但是也还是出现了一些线下培训细节没有勾兑清楚地额沟通问题。接下来,我也会写一篇开发线下项目的经验分享,也非常欢迎和期待各位小伙伴与我们在小程序上有更多的交流合作和技术探讨。
2019-03-19