|
| 1 | +<!-- TOC --> |
| 2 | + |
| 3 | +- [小程序-登录](#小程序-登录) |
| 4 | + - [unionid和openid](#unionid和openid) |
| 5 | + - [关键Api](#关键api) |
| 6 | + - [登录流程设计](#登录流程设计) |
| 7 | + - [利用现有登录体系](#利用现有登录体系) |
| 8 | + - [利用OpenId 创建用户体系](#利用openid-创建用户体系) |
| 9 | + - [利用 Unionid 创建用户体系](#利用-unionid-创建用户体系) |
| 10 | + - [几个注意事项](#几个注意事项) |
| 11 | +- [小程序-图片导出](#小程序-图片导出) |
| 12 | + - [基本原理](#基本原理) |
| 13 | + - [如何优雅实现](#如何优雅实现) |
| 14 | +- [小程序-数据统计](#小程序-数据统计) |
| 15 | +- [小程序-工程化](#小程序-工程化) |
| 16 | + |
| 17 | +<!-- /TOC --> |
| 18 | + |
| 19 | +# 小程序-登录 |
| 20 | + |
| 21 | +## unionid和openid |
| 22 | + |
| 23 | +了解小程序登陆之前,我们写了解下小程序/公众号登录涉及到两个最关键的用户标识: |
| 24 | + |
| 25 | +- `OpenId` 是一个用户对于一个小程序/公众号的标识,开发者可以通过这个标识识别出用户。 |
| 26 | +- `UnionId` 是一个用户对于同主体微信小程序/公众号/APP的标识,开发者需要在微信开放平台下绑定相同账号的主体。开发者可通过UnionId,实现多个小程序、公众号、甚至APP 之间的数据互通了。 |
| 27 | + |
| 28 | +## 关键Api |
| 29 | + |
| 30 | +- [`wx.login`](https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html) 官方提供的登录能力 |
| 31 | + |
| 32 | +- [`wx.checkSession`](https://developers.weixin.qq.com/miniprogram/dev/api/signature.html#wxchecksessionobject) 校验用户当前的session_key是否有效 |
| 33 | + |
| 34 | +- [`wx.authorize`](https://developers.weixin.qq.com/miniprogram/dev/api/authorize.html) 提前向用户发起授权请求 |
| 35 | + |
| 36 | +- [`wx.getUserInfo`](https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html) 获取用户基本信息 |
| 37 | + |
| 38 | + |
| 39 | +## 登录流程设计 |
| 40 | + |
| 41 | + 以下从笔者接触过的几种登录流程来做阐述: |
| 42 | + |
| 43 | +### 利用现有登录体系 |
| 44 | + |
| 45 | + 直接复用现有系统的登录体系,只需要在小程序端设计用户名,密码/验证码输入页面,便可以简便的实现登录,只需要保持良好的用户体验即可。 |
| 46 | + |
| 47 | +### 利用OpenId 创建用户体系 |
| 48 | + |
| 49 | +👆提过,`OpenId` 是一个小程序对于一个用户的标识,利用这一点我们可以轻松的实现一套基于小程序的用户体系,值得一提的是这种用户体系对用户的打扰最低,可以实现静默登录。具体步骤如下: |
| 50 | + |
| 51 | + 1. 小程序客户端通过 `wx.login` 获取 code |
| 52 | + |
| 53 | + 2. 传递 code 向服务端,服务端拿到 code 调用微信登录凭证校验接口,微信服务器返回 `openid` 和会话密钥 `session_key` ,此时开发者服务端便可以利用 `openid` 生成用户入库,再向小程序客户端返回自定义登录态 |
| 54 | + |
| 55 | + 3. 小程序客户端缓存 (通过`storage`)自定义登录态(token),后续调用接口时携带该登录态作为用户身份标识即可 |
| 56 | + |
| 57 | +### 利用 Unionid 创建用户体系 |
| 58 | + |
| 59 | +如果想实现多个小程序,公众号,已有登录系统的数据互通,可以通过获取到用户 unionid 的方式建立用户体系。因为 unionid 在同一开放平台下的所所有应用都是相同的,通过 `unionid` 建立的用户体系即可实现全平台数据的互通,更方便的接入原有的功能,那如何获取 `unionid` 呢,有以下两种方式: |
| 60 | + |
| 61 | + 1. 如果户关注了某个相同主体公众号,或曾经在某个相同主体App、公众号上进行过微信登录授权,通过 `wx.login` 可以直接获取 到 `unionid` |
| 62 | + |
| 63 | + 2. 结合 `wx.getUserInfo` 和 `<button open-type="getUserInfo"><button/>` 这两种方式引导用户主动授权,主动授权后通过返回的信息和服务端交互 (这里有一步需要服务端解密数据的过程,很简单,微信提供了示例代码) 即可拿到 `unionid` 建立用户体系, 然后由服务端返回登录态,本地记录即可实现登录,附上微信提供的最佳实践: |
| 64 | + |
| 65 | + - 调用 wx.login 获取 code,然后从微信后端换取到 session_key,用于解密 getUserInfo返回的敏感数据。 |
| 66 | + |
| 67 | + - 使用 wx.getSetting 获取用户的授权情况 |
| 68 | + - 如果用户已经授权,直接调用 API wx.getUserInfo 获取用户最新的信息; |
| 69 | + - 用户未授权,在界面中显示一个按钮提示用户登入,当用户点击并授权后就获取到用户的最新信息。 |
| 70 | + |
| 71 | + - 获取到用户数据后可以进行展示或者发送给自己的后端。 |
| 72 | + |
| 73 | +### 注意事项 |
| 74 | + |
| 75 | +1. 需要获取 `unionid` 形式的登录体系,在以前(18年4月之前)是通过以下这种方式来实现,但后续微信做了调整(因为一进入小程序,主动弹起各种授权弹窗的这种形式,比较容易导致用户流失),调整为必须使用按钮引导用户主动授权的方式,这次调整对开发者影响较大,开发者需要注意遵守微信的规则,并及时和业务方沟通业务形式,不要存在侥幸心理,以防造成小程序不过审等情况。 |
| 76 | + |
| 77 | +``` |
| 78 | + wx.login(获取code) ===> wx.getUserInfo(用户授权) ===> 获取 unionid |
| 79 | +``` |
| 80 | + |
| 81 | +2. 因为小程序不存在 `cookie` 的概念, 登录态必须缓存在本地,因此强烈建议为登录态设置过期时间 |
| 82 | + |
| 83 | +3. 值得一提的是如果需要支持风控安全校验,多平台登录等功能,可能需要加入一些公共参数,例如platform,channel,deviceParam等参数。在和服务端确定方案时,作为前端同学应该及时提出这些合理的建议,设计合理的系统。 |
| 84 | + |
| 85 | +4. `openid` , `unionid` 不要在接口中明文传输,这是一种危险的行为,同时也很不专业。 |
| 86 | + |
| 87 | + |
| 88 | +# 小程序-图片导出 |
| 89 | + |
| 90 | +经常开发和使用小程序的同学对这个功能一定不陌生,这是一种常见的引流方式,一般同时会在图片中附加一个小程序二维码。 |
| 91 | + |
| 92 | +## 基本原理 |
| 93 | + |
| 94 | +1. 借助 `canvas` 元素,将需要导出的样式首先在 `canvas` 画布上绘制出来 (api基本和h5保持一致,但有轻微差异,使用时注意即可) |
| 95 | + |
| 96 | +2. 借助微信提供的 `canvasToTempFilePath` 导出图片,最后再使用 `saveImageToPhotosAlbum` (需要授权)保存图片到本地 |
| 97 | + |
| 98 | + |
| 99 | +## 如何优雅实现 |
| 100 | + |
| 101 | +根据上述的原理来看,实现是很简单的,只不过就是设计稿的提取,绘制即可,但是作为一个常用功能,每次都这样写一坨代码岂不是非常的难受。那小程序如何设计一个通用的方法来帮助我们导出图片呢?思路如下: |
| 102 | + |
| 103 | +1. 绘制出需要的样式这一步是省略不掉的。但是我们可以封装一个绘制库,包含常见图形的绘制,例如矩形,圆角矩形,圆, 扇形, 三角形, 文字,图片减少绘制代码,只需要提炼出样式信息,便可以轻松的绘制,最后导出图片存入相册。笔者觉得以下这种方式绘制更为优雅清晰一些,其实也可以使用加入一个type参数来指定绘制类型,传入的一个是样式数组,实现绘制。 |
| 104 | + |
| 105 | +2. 结合上一步的实现,如果对于同一类型的卡片有多次导出需求的场景,也可以使用自定义组件的方式,封装同一类型的卡片为一个通用组件,在需要导出图片功能的地方,引入该组件即可。 |
| 106 | + |
| 107 | + |
| 108 | +```js |
| 109 | + |
| 110 | + class CanvasKit { |
| 111 | + constructor() { |
| 112 | + } |
| 113 | + drawImg(option = {}) { |
| 114 | + ... |
| 115 | + return this |
| 116 | + } |
| 117 | + drawRect(option = {}) { |
| 118 | + return this |
| 119 | + } |
| 120 | + drawText(option = {}) { |
| 121 | + ... |
| 122 | + return this |
| 123 | + } |
| 124 | + static exportImg(option = {}) { |
| 125 | + ... |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + let drawer = new CanvasKit('canvasId').drawImg(styleObj1).drawText(styleObj2) |
| 130 | + drawer.exportImg() |
| 131 | + |
| 132 | +``` |
| 133 | + |
| 134 | + |
| 135 | +## 注意事项 |
| 136 | + |
| 137 | +1. 小程序中无法绘制网络图片到canvas上,需要通过downLoadFile 先下载图片到本地临时文件才可以绘制 |
| 138 | +2. 通常需要绘制二维码到导出的图片上,有[一种方式](https://developers.weixin.qq.com/miniprogram/dev/api/qrcode.html)导出二维码时,需要携带的参数必须做编码,而且有具体的长度(32可见字符)限制,可以借助服务端生成 `短链接` 的方式来解决 |
| 139 | + |
| 140 | + |
| 141 | + |
| 142 | + |
| 143 | +# 小程序-数据统计 |
| 144 | + |
| 145 | +数据统计作为目前一种常用的分析用户行为的方式,小程序端也是必不可少的。小程序采取的曝光,点击数据埋点其实和h5原理是一样的。但是埋点作为一个和业务逻辑不相关的需求,我们如果在每一个点击事件,每一个生命周期加入各种埋点代码,则会干扰正常的业务逻辑,和使代码变的臃肿,笔者提供以下几种思路来解决数据埋点: |
| 146 | + |
| 147 | +## 设计一个埋点sdk |
| 148 | + |
| 149 | +小程序的代码结构是,每一个 Page 中都有一个 Page 方法,接受一个包含生命周期函数,数据的 `业务逻辑对象` 包装这层数据,借助小程序的底层逻辑实现页面的业务逻辑。通过这个我们可以想到思路,对Page进行一次包装,篡改它的生命周期和点击事件,混入埋点代码,不干扰业务逻辑,只要做一些简单的配置即可埋点,简单的代码实现如下: |
| 150 | + |
| 151 | +```js |
| 152 | + |
| 153 | + 代码仅供理解思路 |
| 154 | + page = function(params) { |
| 155 | + let keys = params.keys() |
| 156 | + keys.forEach(v => { |
| 157 | + if (v === 'onLoad') { |
| 158 | + params[v] = function(options) { |
| 159 | + stat() //曝光埋点代码 |
| 160 | + params[v].call(this, options) |
| 161 | + } |
| 162 | + } |
| 163 | + else if (v.includes('click')) { |
| 164 | + params[v] = funciton(event) { |
| 165 | + let data = event.dataset.config |
| 166 | + stat(data) // 点击埋点 |
| 167 | + param[v].call(this) |
| 168 | + } |
| 169 | + } |
| 170 | + }) |
| 171 | + } |
| 172 | +``` |
| 173 | + |
| 174 | + 这种思路不光适用于埋点,也可以用来作全局异常处理,请求的统一处理等场景。 |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | +## 分析接口 |
| 179 | + |
| 180 | +对于特殊的一些业务,我们可以采取 `接口埋点`,什么叫接口埋点呢?很多情况下,我们有的api并不是多处调用的,只会在某一个特定的页面调用,通过这个思路我们可以分析出,该接口被请求,则这个行为被触发了,则完全可以通过服务端日志得出埋点数据,但是这种方式局限性较大,而且属于分析结果得出过程,可能存在误差,但可以作为一种思路了解一下。 |
| 181 | + |
| 182 | +## [微信自定义数据分析](https://developers.weixin.qq.com/miniprogram/analysis/index.html?t=18081011) |
| 183 | + |
| 184 | +微信本身提供的数据分析能力,微信本身提供了常规分析和自定义分析两种数据分析方式,在小程序后台配置即可。借助`小程序数据助手`这款小程序可以很方便的查看。 |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | +# 小程序-工程化 |
| 190 | + |
| 191 | +## 工程化做什么 |
| 192 | + |
| 193 | +目前的前端开发过程,工程化是必不可少的一环,那小程序工程化都需要做些什么呢,先看下目前小程序开发当中存在哪些问题需要解决: |
| 194 | + |
| 195 | +1. 不支持 css预编译器,作为一种主流的 css解决方案,不论是 less,sass,stylus 都可以提升css效率 |
| 196 | +2. 不支持引入npm包 (这一条,从微信公开课中听闻,微信准备支持) |
| 197 | +3. 不支持ES7等后续的js特性,好用的async await等特性都无法使用 |
| 198 | +4. 不支持引入外部字体文件,只支持base64 |
| 199 | +5. 没有 eslint 等代码检查工具 |
| 200 | + |
| 201 | +## 方案选型 |
| 202 | + |
| 203 | +对于目前常用的工程化方案,webpack,rollup,parcel等来看,都常用与单页应用的打包和处理,而小程序天生是 “多页应用” 并且存在一些特定的配置。根据要解决的问题来看,无非是文件的编译,修改,拷贝这些处理,对于这些需求,我们想到基于流的 `gulp`非常的适合处理,并且相对于webpack配置多页应用更加简单。所以小程序工程化方案推荐使用 `gulp` |
| 204 | + |
| 205 | +## 具体开发思路 |
| 206 | + |
| 207 | +通过 gulp 的 task 实现: |
| 208 | + |
| 209 | +1. 实时编译 less 文件至相应目录 |
| 210 | +2. 引入支持async,await的运行时文件 |
| 211 | +3. 编译字体文件为base64 并生成相应css文件,方便使用 |
| 212 | +4. 依赖分析哪些地方引用了npm包,将npm包打成一个文件,拷贝至相应目录 |
| 213 | +5. 检查代码规范 |
| 214 | + |
| 215 | +上述实现起来其实并不是很难,但是这样的话就是一份纯粹的 gulp 构建脚本和 约定好的目录而已,每次都有一个新的小程序都来拷贝这份脚本来处理吗?显然不合适,那如何真正的实现 `小程序工程化` 呢? |
| 216 | +我们可能需要一个简单的脚手架,脚手架需要支持的功能: |
| 217 | + |
| 218 | +1. 支持新建项目,创建Page,创建Component |
| 219 | +2. 支持内置构建脚本 |
| 220 | +3. 支持发布小程序,也可以想办法接入Jenkins等工具做持续集成 (小程序持续集成后面会提) |
| 221 | +... |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | + |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
| 233 | + |
| 234 | + |
| 235 | + |
| 236 | + |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | + |
| 241 | + |
| 242 | + |
| 243 | + |
| 244 | + |
| 245 | + |
| 246 | + |
| 247 | + |
| 248 | + |
| 249 | + |
| 250 | + |
| 251 | + |
| 252 | + |
| 253 | + |
| 254 | + |
| 255 | + |
| 256 | + |
| 257 | + |
| 258 | + |
| 259 | + |
| 260 | + |
| 261 | + |
| 262 | + |
| 263 | + |
0 commit comments