- 从想法到上线千万访问量的产品,1个开发就搞定,如何做到?
11月29日,腾讯云与微信小程序团队联合举办的第二届小程序·云开发技术峰会在北京举行,在会上有众多来自不同行业,不同实践者的案例分享,讲述了各自与云开发的故事…… 每一个准确把握技术浪潮的人,都是时代的幸运儿。 本篇课程,和大家分享群登记助手的云开发实践案例与经验。 群登记助手 因为今年疫情,线下多种场景需要登记,且大多是接触式登记,为了避免接触风险。所以我做了这款「群登记助手」,实现零接触的云登记。那么它有什么功能呢? [图片] 主要分为三个核心模块: 第一,作业登记:主要解决线上交作业,自动统计提交情况,批改及评价作业;且支持图文、视频、语音多种作业类型。 第二,报名接龙:支持健康信息接龙、班级接龙、报名接龙,可自定义收集表单项,及在线导出数据。 第三,出入登记:用于社区、小区、医院、学校、公司扫码出入登记防控管理,做到无接触式登记。 [图片] 到目前为止这款产品一共为 12 万收集者赋能,帮助他们收集登记信息。累计收集近 600 万份登记数据,达到数千万次访问,实现无接触登记,将接触风险降至为 0 技术架构 接下来,我们来看看这个项目背后的技术架构。 首先小程序端采用的是原生的写法,自己封装了一些常用组件,然后还抽出了一个 API 层,专门用于云函数的管理。 [图片] 举个业务场景:学生需要登记作业,老师要求上传作业照片。这个时候小程序直接调用云存储的接口进行图片存储,存储成功后获取到一个图片地址;小程序在用这个地址请求云函数,存储到云数据库当中。 在这个过程中为了内容安全得到保障,还会用到云调用的文字内容检查接口和图片内容检查接口。 除此之外还用到了云扩展的一些应用。如: 内容管理系统:方便开发人员和内容运营者,随时随地管理小程序云开发内容数据。 博客系统:用于作为官网,记录并分享产品迭代及产品使用教程。 图片处理:主要是用它的快速压缩模版,为了减少 CDN 流量消耗。 说完技术架构后,我们再来看下这套架构的整体性能表现。从性能体验报告来看,无论是启动性能,页面加载性能,还是接口性能,网络性能及多媒体性能表现都非常不错的,综合性能评定为优秀。 [图片] 心路历程 接下来,我再说说在技术选型时的心路历程。 这款产品想法诞生的时候,我其实是有一些顾虑,主要因为两个方面: 第一,我没有做过后端开发,也不懂服务器运维。 第二,域名备案,小程序后台接口请求需要配置已备案的 https 域名,而备案域名至少需要一周左右的时间。 通过这两个问题引发了我的一个思考,我怎么样才能更快的上线呢?不懂后端开发,有想过找一个后端开发合作。先不说别人愿不愿意,就算愿意,沟通成本也非常高。 域名备案时间难道只能等?大家要知道,一款产品上线速度十分重要。特别没有资源的独立开发者,上线的时间越早越好,才能获取到更多到用户。 我灵光一现,想到了云开发解决方案。它完美的解决了我的刚提到的两个问题: 第一,无需服务器搭建和运维。因为云开发是云端一体化的后端云服务 ,采用 serverless 架构,免去了服务器搭建和运维。 第二,它无需配置业务域名,直接调用云函数里面即可。解决域名备案等待时间过长的问题。我只需要做好业务代码实现就够了所以我选择了云开发。最后很快就上线了。 第一版开发,我 1 个人仅用了 3 天时间,并且这 3 天还是下班之余的时间。从 2 月份这个项目启动,到现在经历了 9 个多月的时间,一共累计 40 多次迭代。而在这段时间里云开发本身也在不断的优化。 说完技术选型的心路历程,再说说我在实践中的小插曲 [图片] 在上图中,CDN 流量消耗和存储读请求次数特别大,这是因为在大量的登记里面上传图片需求非常高频,加上当时群登记助手日活高达 4w。使得我原本采购的 CDN 3(2199/月)套餐完全抗不住这个 CDN 消耗。 所以我直接升级到旗舰 3 套餐。这个套餐每月 4699/月,对于一名独立开发者来说,这个成本非常高。 于是我在「微信开放社区」进行了提问,我说什么时候能推出按需计费?当天就得到了官方人员的回复,已经支持了。 [图片] 在迅速切换完成按量付费模式后,效果很明显,成本直接从每个月 4699 降低到了 2 千多,整体费用降低了 1 倍。 但是这成本还是有点小贵。后来经过云开发团队的不断的迭代优化,推出了云扩展的【图片处理】服务。我使用了图片处理服务的快速压缩模版,使得成本再一次的降低。上次是 1 倍,这次是 10 倍,从原来的 2249 变成了现在的 2 百多,这个成本可以说很低了。 [图片] 上手建议 说完小插曲,我相信你一定迫不及待的想要学习云开发了,那我就聊聊快速上手云开发的小建议。 推荐你 3 个官方学习网站。 第一,官方文档,写的非常详细。每个都有案例,代码 copy 过来改一改参数就直接能用,相信这让会让你更快的上手实践。 [图片] 第二,如果你不喜欢看文档,腾讯云大学还出品了云开发的优质视频教程;文档可以作为类似字典的存在,用于查询具体技术的细节。 [图片] 第三,其实就是我刚有提到过的「微信开放社区」。我在开发群登记助手的时候就在这里提了不少问题,问题响应速度非常快。 [图片] 还有就是无论是文档还是教学视频,总会有些无法覆盖的问题。这个时候遇到问题就到社区提问。这里除了有很多官方人员回答,还有很多优秀的小程序开发者也会在这里,去解答问题和分享一些开发经验,社区整体氛围很不错。 我在这个社区也比较活跃,回答过上千个问题,在这里我想说两个提问技巧,能有效提高你解决问题的速度。 第一,提问之前先搜索,也许你的问题已经有解决方案了,就没必要再次提出重复的问题。 第二,提问尽量把问题描述清晰一些,如果有关代码的问题,最好附带上代码片段。这样便于回答者更快速解答问题。 总结 最后说下自己的感想,我相信每个程序都有想做一款好产品的梦想,云开发就像这个梦想的助力器,在我们开发产品过长中,极大程度地降低了开发成本。 感谢云开发,让曾经不可能一个人能完成的任务,现在变得十分简单! [图片] 云开发,让开发者成为真正的全栈工程师,感谢你阅读我的分享。 作者简介:腾讯《小程序云开发挑战赛》职业组第一,Android 知名开源库 BRVAH 作者,公众号「码个蛋」主理人。通过云开发开发过 10 多款小程序,累计访问量超千万。本文编辑自云开发峰会现场讲稿,有些文字进行了书面化处理,并匹配结合现场PPT
2020-12-16 - 基于云开发的应用热更新实践
应用配置热更新不是什么新鲜事,但是基于云开发的实践又是怎样的呢? 腾讯出行插件 腾讯出行插件,是为腾讯乘车码用户提供实时公交,线路规划,地铁图等便捷出行的服务。 [图片] 频繁的数据变更 乘车码目前覆盖了数十个城市, 每天,每个城市都有一些数据的变更需求, 比如线路等 。虽然每个城市的变更都不多,但全国数十个城市累计下来,每天还是会有不少数据需要变更。而这些变更,从产品到设计,最终会流通到开发团队,由开发团队进行代码层面到配置更改。 一般情况下,一个数据更新需求,大致需要走完这样一个流程: [图片] 所以,看似简单的需求,但算上应用开发的时间、应用维护的成本、开发团队的其他工作、微信的审核时长等因素,小程序开发的迭代并没有想象中那么快,正常情况下迭代一个版本需要 1 ~ 3 天的时间。 可是,全国线路变更必须尽快上线,而且每天都会有数据的变更。这些高频大量的数据变更需求,给开发团队带来了巨大的考验:如何花最少的时间,确保线路数据部署上线? 面临挑战的开发团队想到了采用热更新来解决这个问题。 一般来说,在现有的后台配置热更新等相关内容,也会花费大量的时间和精力,而且还需要进行需求的排期。有没有别的办法来实现应用配置热更新呢? 基于云开发的应用配置热更新 在这样的情况下,开发团队了解到了云开发,云开发提供的小程序端直连数据库,以及方便易用的管理控制台,非常适合配置的快速变更与业务侧的快速拉取,所以我们决定使用云开发来完成应用配置的热更新。 开发团队将涉及到线路、需要变更的配置写入到云开发的数据库中,使用云开发的数据库来进行配置的存储,这样就可以在小程序启动时,调用云开发的云数据库,查询配置信息,并分发到小程序中。云开发提供的高性能数据库确保了数据的及时下发和使用,帮助开发团队完成配置的分发需求。 [图片] 得益于云开发数据库本身提供的配置界面,开发团队快速地完成配置变更,从而满足产品需求,完成快速的配置更新和迭代。当有新的变更请求提供给开发团队时,开发团队最快可以在0.5小时内完成配置的更新及下发,大大的提升了数据的准确性。
2020-11-03 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~ 这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能) 咱们不多说,直接上手就是干。 [图片] 首先我们新增一个自定义组件,在该组件的json中引入painter [代码]{ "component": true, "usingComponents": { "painter": "/painter/painter" } } [代码] 然后组件的WXML (代码片段在最后) [代码]// 将该组件定位在屏幕之外,用户查看不到。 <painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" /> [代码] 重点来了 JS (代码片段在最后) [代码]Component({ properties: { // 是否开始绘图 isCanDraw: { type: Boolean, value: false, observer(newVal) { newVal && this.handleStartDrawImg() } }, // 用户头像昵称信息 userInfo: { type: Object, value: { avatarUrl: '', nickName: '' } } }, data: { imgDraw: {}, // 绘制图片的大对象 sharePath: '' // 生成的分享图 }, methods: { handleStartDrawImg() { wx.showLoading({ title: '生成中' }) this.setData({ imgDraw: { width: '750rpx', height: '1334rpx', background: 'https://qiniu-image.qtshe.com/20190506share-bg.png', views: [ { type: 'image', url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg', css: { top: '32rpx', left: '30rpx', right: '32rpx', width: '688rpx', height: '420rpx', borderRadius: '16rpx' }, }, { type: 'image', url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png', css: { top: '404rpx', left: '328rpx', width: '96rpx', height: '96rpx', borderWidth: '6rpx', borderColor: '#FFF', borderRadius: '96rpx' } }, { type: 'text', text: this.data.userInfo.nickName || '青团子', css: { top: '532rpx', fontSize: '28rpx', left: '375rpx', align: 'center', color: '#3c3c3c' } }, { type: 'text', text: `邀请您参与助力活动`, css: { top: '576rpx', left: '375rpx', align: 'center', fontSize: '28rpx', color: '#3c3c3c' } }, { type: 'text', text: `宇宙最萌蓝牙耳机测评员`, css: { top: '644rpx', left: '375rpx', maxLines: 1, align: 'center', fontWeight: 'bold', fontSize: '44rpx', color: '#3c3c3c' } }, { type: 'image', url: 'https://qiniu-image.qtshe.com/20190605index.jpg', css: { top: '834rpx', left: '470rpx', width: '200rpx', height: '200rpx' } } ] } }) }, onImgErr(e) { wx.hideLoading() wx.showToast({ title: '生成分享图失败,请刷新页面重试' }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') }, onImgOK(e) { wx.hideLoading() // 展示分享图 wx.showShareImageMenu({ path: e.detail.path, fail: err => { console.log(err) } }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') } } }) [代码] 那么我们该如何引用呢? 首先json里引用我们封装好的组件share-box [代码]{ "usingComponents": { "share-box": "/components/shareBox/index" } } [代码] 以下示例为获取用户头像昵称后再生成图。 [代码]<button class="intro" bindtap="getUserInfo">点我生成分享图</button> <share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}" bind:initData="handleClose" /> [代码] 调用的地方: [代码]const app = getApp() Page({ data: { isCanDraw: false }, // 组件内部关掉或者绘制完成需重置状态 handleClose() { this.setData({ isCanDraw: !this.data.isCanDraw }) }, getUserInfo(e) { wx.getUserProfile({ desc: "获取您的头像昵称信息", success: res => { const { userInfo = {} } = res this.setData({ userInfo, isCanDraw: true // 开始绘制海报图 }) }, fail: err => { console.log(err) } }) } }) [代码] 最后绘制分享图的自定义组件就完成啦~效果图如下: [图片] tips: 文字居中实现可以看下代码片段 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号 代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5 附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。 最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
2022-01-20