车辆激活(扫码激活)的实现
一、业务场景
车辆激活是在车端大屏幕上生成一个二维码,车主使用App进行扫码,点击“确认激活”,车端收到指令后,由相应的模块(一般是CDC)进行本地激活。
二、激活流程图
sequenceDiagram
participant Car as 车端
participant Cloud as 云端
participant MQTT as MQTT网关
participant OwnerApp as 车主App
Car->>Cloud: 1.1 请求生成二维码ID
Cloud->>MQTT: 1.2 通过MQTT下发二维码ID
MQTT->>Car: 1.3 接收二维码ID
Car->>Car: 1.4 生成二维码并显示在大屏幕上
OwnerApp->>Car: 2.1 扫描二维码,获取二维码ID
OwnerApp->>Cloud: 2.2 将二维码ID发给云端
Cloud->>Cloud: 2.3 将二维码状态更新为“已扫描”
OwnerApp->>OwnerApp: 2.4 显示“确认激活”按钮
OwnerApp->>Cloud: 3.1 点击“确认激活”,发送激活指令
Cloud->>Cloud: 3.2 将二维码状态更新为“已确认”
Cloud->>MQTT: 3.3 通过MQTT下发激活指令
MQTT->>Car: 3.4 下发激活指令
Car->>Car: 4.1 车端CDC接收指令并进行本地激活
三、激活流程
3.1 车端生成二维码
该阶段是车端跟云端的交互过程。
- 用户提车后,打开车端大屏幕,发起激活请求,云端在接收到这一请求时,会生成一个唯一的二维码ID,并将该ID转化为Base64编码的字符串,通过MQTT下发给车端。
- 该二维码ID一定是唯一的,后续流程会将二维码ID跟车辆ID绑定,用于后续操作的校验。
- 车端会启动一个定时器,轮询查询二维码是否被扫描,如果未被App扫描,隔一段时间二维码会自动刷新。
3.2 App扫描二维码
该阶段是客户端跟云端的交互过程。
- App扫描二维码,解析出二维码ID,将二维码ID作为参数发送给云端。
- 云端接到请求后,会通过二维码 ID 查找Redis缓存进行校验,校验通过后,将二维码状态更新为“已扫描”。
- App接收到扫码请求成功的结果后,会跳转到激活页面,请车主在手机App端确认激活。
3.3 App确认激活
该阶段是客户端、车端跟服务端的交互过程。
- 用户点击“确认激活”按钮,仍然是将二维码ID作为参数发送给服务端。
- 云端接到请求后,会通过二维码 ID 查找Redis缓存进行校验,校验通过后,将二维码状态更新为“已确认”。
- 云端将激活信息(二维码ID等)通过MQTT下发给车。
四、遇到的问题
在研发、联调过程中,存在几个问题:
4.1 云端和车端数据不一致的问题
问题描述
在App确认激活阶段,云端先将车辆激活状态置为“已激活”,再将激活信息下发给车端,但经常遇到车辆不在线、网关服务不稳定,导致激活信息不能正常下发给车端。
解决方案
修改技术方案,将流程修改为:
- App确认激活时,云端不再更新二维码状态为“已确认”,而是生成一个激活安全码下发给车端。
- 车端主动上报激活时,要携带这个云端下发的激活安全码,如没收到,则需要重复扫码过程。
- 车端可以多次上报激活,云端可以判断云端的激活状态,如果激活成功,直接返回结果;如果是“未激活”,则将激活状态修改为“已激活”。
- 至此,车端云端的数据可以保持一致。
新的激活流程如下:
sequenceDiagram
participant Car as 车端
participant Cloud as 云端
participant MQTT as MQTT网关
participant OwnerApp as 车主App
Car->>Cloud: 1.1 请求生成二维码ID
Cloud->>MQTT: 1.2 通过MQTT下发二维码ID
MQTT->>Car: 1.3 接收二维码ID
Car->>Car: 1.4 生成二维码并显示在大屏幕上
OwnerApp->>Car: 2.1 扫描二维码,获取二维码ID
OwnerApp->>Cloud: 2.2 将二维码ID发给云端
Cloud->>Cloud: 2.3 将二维码状态更新为“已扫描”
OwnerApp->>OwnerApp: 2.4 显示“确认激活”按钮
OwnerApp->>Cloud: 3.1 点击“确认激活”,发送激活指令
Cloud->>MQTT: 3.2 通过MQTT下发激活安全码
MQTT->>Car: 3.3 下发激活安全码
Car->>Cloud: 4.1 车端上报激活
Cloud->>Cloud: 4.2 (车辆未激活时)更新车辆激活状态
Clout->>MQTT: 4.3 通过MQTT下发激活结果
MQTT->>Car: 4.4 下发激活结果
4.2 二维码密度过大问题
问题描述
二维码通常具有一定的容错能力,二维码图案即使被遮挡了一小部分,也可以正常扫描。但如果二维码密度过大,会降低其对污点、遮挡度的容忍度,影响扫码的成功率,进而影响用户的感官体验。
目前车端请求生成二维码的步骤为:
- 拼接原始内容字符串:用户ID、车辆ID、主副驾位置
- 生成二维码ID:qrcodeID=base64(AESCFB(原始内容,私钥)),生成的长度大约在100字符以上。
- 生成二维码所需的内容:一个url和qrcodeID拼接的字符串,形同 url/active?info=qrcodeID。
- 生成二维码图片流:qrcode=Base64(生成的二维码图片字节流),30%容错,尺寸:300x300px
因为二维码密度主要与二维码所需内容长度有关,前面 url 长度固定,占60个字符,qrcodeID 约占100个字符,总长度160+个字符,只有缩短 qrcodelD 的长度才可以降低二维码密度。
解决方案
- 生成二维码ID不再使用AES和base64加密,使用uuid,生成的长度是32个字符。
- 新增缓存,将一些原始内容进行缓存,这里使用的是字符串,key是二维码ID,value是用户ID、车辆ID等字段拼接起来的字符串。
- App扫码/确认激活/取消激活,先根据qrcodeID从缓存中获取缓存信息,再进行相应的处理。