Skip to content

小程序系列

理解微信小程序

  • 微信小程序是什么

小程序是一种不需要下载安装即可使用的应用

  • JS-SDK

解决了移动⽹⻚能⼒不⾜的问题,通过暴露微信的接⼝使得 Web 开发者能够拥有更多的能⼒,然⽽在更多的能⼒之外,JS-SDK的模式并没有解决使⽤移动⽹⻚遇到的体验不良的问题

  • 小程序与H5的区别有如下
  • 运⾏环境:⼩程序基于浏览器内核重构的内置解析器
  • 系统权限:⼩程序能获得更多的系统权限,如⽹络通信状态、数据缓存能⼒等
  • 渲染机制:⼩程序的逻辑层和渲染层是分开的
  • 局限

小程序可以视为只能用微信打开和浏览的H5

  • 优点
  • 随时可用,用完即走,无需安装卸载
  • 安全
  • 开发门槛低
  • 降低兼容性限制
  • 缺点
  • 用户留存:小程序的平均次日留存在13%左右,但是双周留存骤降到仅有1%
  • 体积限制:微信小程序只有2M的大小,这样导致无法开发大型一些的小程序
  • 受控微信:小程序要面对很多来自微信的限制,从功能接口,甚至到类别内容,都要接受微信的管控

微信小程序架构图

微信小程序采用双线程架构,渲染层与逻辑层分离,通过微信客户端(Native)进行中转通信

  • 逻辑层(App Service):包含 managerAPI,负责业务逻辑处理,通过 JSBridge 向渲染层发送 Data、接收 Event
  • 视图层(View):每个页面由 WXML 模板与 WXSS 样式构成,多页面可同时存在,通过 JSBridge 接收 Data、上报 Event
  • JSBridge:逻辑层与视图层之间的通信桥梁,同时连接底层 Native 能力
  • Native 能力:包括微信能力、离线存储、网络请求等,由微信客户端提供

微信小程序的登录流程

登录流程

1️⃣ 微信小程序的登录流程图如下图所示

2️⃣微信小程序的登录步骤

  • ① 获取当前登录微信用户的临时登录凭证(code)。
    • 调用 wx.login() 获取 code
    • 调用 wx.getUserInfo() 获取用户数据(encryptedDataiv)。
  • ② 通过 appid + appsecret+ code,换取 openidsession_key
    • 请求我们自己的后台服务器,将临时登录凭证(code)传给后端。
    • 后端把 appidappsecretcode 一起发送到微信服务器。
    • 微信服务器返回用户的唯一标识 openid 和会话密钥 session_key给自己的业务后端。
  • ③ 拿到 openid 后将其存到数据库中,后端根据openid生成一个自定义登录态(如JWT token),返回给小程序端。
  • ④ 小程序端保存登录态并后续携带

流程说明

角色动作说明
小程序 → 微信wx.login()调用微信接口获取临时 code
小程序 → 开发者服务器发送 code通过 wx.requestcode 传给后端
开发者服务器 → 微信登录凭证校验后端携带 appid + secret + code 调用微信接口
开发者服务器关联登录态生成自定义登录态,与 openidsession_key 关联存储
开发者服务器 → 小程序返回自定义登录态如返回 JWT tokensessionId
小程序存储登录态存入 wx.setStorageSync 供后续使用
小程序 ↔ 开发者服务器后续业务请求每次请求携带自定义登录态,后端校验后返回业务数据

扩展

实际业务中,我们还需要检查登录态是否过期,通常的做法是在登录态(临时令牌)中保存有效期数据,该有效期数据应该在服务端校验登录态时和约定的时间(如服务端本地的系统时间或时间服务器上的标准时间)做对比

这种方法需要将本地存储的登录态发送到小程序的服务端,服务端判断为无效登录态时再返回需重新执行登录过程的消息给小程

另一种方式可以通过调用wx.checkSession检查微信登录态是否过期

  • 若过期,则发起完整的登录流程
  • 若不过期,则继续使用本地保存的自定义登录态

注意事项

注意事项

  • 由于我们自己的小程序后台授权域名无法授权微信的域名,所以我们只能通过我们自己的服务器去调用微信服务器去获取用户信息。
  • 临时登录凭证 code,有效期5分钟。
  • code 只能使用一次,用于换取用户身份信息。
  • AppIDAppSecret(小程序密钥)是在微信公众平台创建好小程序后,由微信官方分配给你的。
  • AppSecret非常重要,绝不能像 AppID 那样直接写在客户端代码里,它只能在你受信任的后端服务器中使用。
  • openid 用户的唯一标识。
  • session_key 是对用户数据进行加密签名的密钥。
  • session_key 不应返回给前端,只保存在后端用于后续解密。

补充说明

如果需要获取用户信息(头像、昵称)

  • 2022 年起,wx.getUserInfo 不再直接弹出授权框,需要使用 wx.getUserProfile(但该接口也在逐步调整)。

参考文献

微信小程序的发布流程

流程

  • 上传代码: 在开发者工具中上传代码,可以填写版本信息。
  • 提交审核: 代码上传完毕,可在微信公众平台后台提交审核,需要填写审核信息。
  • 发布版本: 当审核通过之后,即可提交发布。

扩展

通常的流程如下

  • 代码管理服务器上新建分支
  • 开发测试新需求
  • 测试完成后,将本地分支合并到 master 分支
  • 拉取 master 分支最新代码,执行 build 命令生成小程序可执行文件
  • 开发者工具点击“上传”
  • 提审
  • 发布

参考文献

微信小程序的支付流程

支付前言

在小程序内可调用微信的API完成支付功能,方便、快捷

  • 用户通过分享或扫描二维码进入商户小程序,用户选择购买,完成选购流程
  • 调起微信支付控件,用户开始输入支付密码
  • 密码验证通过,支付成功。商户后台得到支付成功的通知
  • 返回商户小程序,显示购买成功
  • 微信支付公众号下发支付凭证

支付流程

1️⃣ 微信小程序支付流程图如下图示

2️⃣ 微信小程序支付步骤

  • 打开某小程序,点击直接下单
  • wx.login()获取用户临时登录凭证code,发送到后端服务器换取openId
  • 在下单时,小程序需要将购买的商品Id商品数量,以及用户的 openId 传送到服务器
  • 服务器在接收到商品Id商品数量openId后,生成服务期订单数据,同时经过一定的签名算法,向微信支付发送请求,获取预付单信息(prepay_id),同时将获取的数据再次进行相应规则的签名,向小程序端响应必要的信息
  • 小程序端在获取对应的参数后,调用wx.requestPayment()发起微信支付,唤醒支付工作台,进行支付
  • 接下来的一些列操作都是由用户来操作的,包括了微信支付密码,指纹等验证,确认支付之后执行鉴权调起支付
  • 鉴权调起支付,在微信后台进行鉴权,微信后台直接返回给前端支付的结果,前端收到返回数据后对支付结果进行展示
  • 推送支付结果,微信后台在给前端返回支付的结果后,也会向后台也返回一个支付结果,后台通过这个支付结果来更新订单的状态

📚 其中后端响应数据必要的信息则是wx.requestPayment()方法所需要的参数,大致如下

js
wx.requestPayment({
  timeStamp: "", // 时间戳
  nonceStr: "", // 随机字符串
  package: "", // 统一下单接口返回的 prepay_id 参数值
  signType: "", // 签名类型
  paySign: "", // 签名
  success() {}, // 调用成功回调
  fail() {}, // 失败回调
  complete() {}, // 接口调用结束回调
});

重新支付

1️⃣ 针对用户下单后未立即支付的情况,实现重新支付功能的核心原则是

使用相同商户订单号(out_trade_no)再次调用微信支付统一下单接口

微信支付接口具有幂等性设计,只要请求参数与原订单完全一致,接口会返回相同的支付参数(如 prepay_id),商户即可用这些参数再次拉起微信支付收银台,无需创建新订单

2️⃣ 微信小程序重新支付流程图如下图示

3️⃣ 微信小程序重新支付流程步骤如下

  • 用户在小程序/APP 前端页面点击重新支付按钮。
  • 前端向商户后端发起重新支付请求(携带原订单号)。
  • 商户后端收到请求后,调用微信支付的统一下单 API(参数中使用原商户订单号)。
  • 微信支付返回 prepay_id 等支付参数给商户后端。
  • 商户后端将这些支付参数返回给前端。
  • 前端调用 wx.requestPayment() 方法,拉起微信支付。
  • 用户完成支付。

4️⃣ 支付结果确认与查单机制

  • 前端轮询

在调起支付后,前端应立即启动轮询,定期调用后端的“查单接口”,根据订单的最终状态更新页面(通常建议间隔2-5秒,持续60秒左右)。

  • 后端查单

后端必须实现一个稳定的“查单接口”。如果前端长时间未收到支付结果,用户再次进入订单页时,应自动触发查单动作,确保订单状态同步。

  • 异步回调

确保后端正确处理微信支付的异步结果通知。无论用户是否在支付页面等待,这个回调都会更新订单状态。

参考文献

微信小程序的实现原理

背景

网页开发,渲染线程和脚本是互斥的,如长时间的脚本运行可能会导致页面失去响应的原因,本质就是 JS 是单线程的。 而在小程序中,选择了 Hybrid 的渲染方式,将视图层和逻辑层是分开的,双线程同时运行,视图层的界面使用 WebView 进行渲染,逻辑层运行在 JSCore

  • 渲染层

界面渲染相关的任务全都在 WebView 线程里执行。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程

  • 逻辑层

采用 JsCore 线程运行 JS 脚本,在这个环境下执行的都是有关小程序业务逻辑的代码

通信

在逻辑层发生数据变更的时候,通过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,再经过对比前后差异,把差异应用在原来的DOM树上,渲染出正确的视图

当视图存在交互的时候,例如用户点击你界面上某个按钮,这类反馈应该通知给开发者的逻辑层,需要将对应的处理状态呈现给用户;对于事件的分发处理,微信进行了特殊的处理,将所有的事件拦截后,丢到逻辑层交给JavaScript进行处理

由于小程序是基于双线程的,也就是任何在视图层和逻辑层之间的数据传递都是线程间的通信,会有一定的延时,因此在小程序中,页面更新成了异步操作。异步会使得各部分的运行时序变得复杂一些,比如在渲染首屏的时候,逻辑层与渲染层会同时开始初始化工作,但是渲染层需要有逻辑层的数据才能把界面渲染出来

运行机制

1️⃣ 小程序启动运行两种情况

  • 冷启动(重新开始)

用户首次打开或者小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动,即为冷启动

  • 热启动

用户已经打开过小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需要将后台态的小程序切换到前台,这个过程就是热启动

注意事项

  • 1.小程序没有重启的概念
  • 2.当小程序进入后台,客户端会维持一段时间的运行状态,超过一定时间后会被微信主动销毁
  • 3.短时间内收到系统两次以上内存警告,也会对小程序进行销毁,这也就为什么一旦页面内存溢出,页面会奔溃的本质原因了

参考文献

提升微信小程序的速度

小程序启动

小程序启动,微信会在背后完成几项工作

  • 下载小程序代码包
  • 加载小程序代码包
  • 初始化小程序首页

下载到的小程序代码包不是小程序的源代码,而是编译、压缩、打包之后的代码包

解决方案

加载

1️⃣ 提升体验最直接的方法是控制小程序包的大小

  • 代码包的体积压缩可以通过勾选开发者工具中“上传代码时,压缩代码”选项
  • 及时清理无用的代码和资源文件
  • 减少资源包中的图片等资源的数量和大小(理论上除了小icon,其他图片资源从网络下载),图片资源压缩率有限

2️⃣ 分包

并且可以采取分包加载的操作,将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载

渲染

1️⃣ 关于微信小程序首屏渲染优化的手段如下

  • 请求可以在页面onLoad就加载,不需要等页面ready后在异步请求数据
  • 尽量减少不必要的https请求,可使用 getStorageSync()setStorageSync() 方法将数据存储在本地
  • 可以在前置页面将一些有用的字段带到当前页,进行首次渲染(列表页的某些数据--> 详情页),没有数据的模块可以进行骨架屏的占位
  • 避免页面节点嵌套过深,增加页面渲染压力

2️⃣ 提高页面的多次渲染效率主要在于正确使用setData

  • 不要过于频繁调用setData,应考虑将多次setData合并成一次setData调用
  • 数据通信的性能与数据量正相关,因而如果有一些数据字段不在界面中展示且数据结构比较复杂或包含长字符串,则不应使用setData来设置这些数据
  • 与界面渲染无关的数据最好不要设置在data中,可以考虑设置在page对象的其他字段下

总结

1️⃣ 小程序启动加载性能

  • 控制代码包的大小
  • 分包加载
  • 首屏体验(预请求,利用缓存,避免白屏,及时反馈)

2️⃣ 小程序渲染性能

  • 避免不当的使用 setData
  • 使用自定义组件

参考文献