Files
hms/docs/discussions/2026-05-30-veepoo-sdk-integration-flow.md
iven 6d073840aa docs(wiki): 记录 Veepoo M2 BLE SDK 对接踩坑和正确流程
- wiki/index.md 症状导航新增 5 条:??语法错误、useRef白屏、扫描匹配、认证超时三层根因
- wiki/index.md 关键数字更新:Git 提交 1061 次,小程序描述补充原生分包页面
- docs/discussions/ 新增 SDK 对接流程文档:
  - 连接回调 4 次触发机制(只响应 connection:true)
  - veepooWeiXinSDKNotifyMonitorValueChange 必须在连接后注册
  - VPDeviceAck vs VPDevicepassword 字段区别
  - deviceChipStatus 布尔值兼容
  - 完整踩坑清单(9 项)
2026-05-30 23:07:03 +08:00

7.1 KiB
Raw Blame History

Veepoo M2 BLE SDK 正确对接流程

日期: 2026-05-30 | 参与者: iven, Claude 状态: 已验证通过

背景

Veepoo M2 手环的 BLE SDK372KB Webpack 打包)在微信小程序中的对接遇到了多层问题。 本文档记录经过实际验证的正确对接流程和踩过的坑,避免后续开发者重复踩坑。

SDK 架构

Taro 页面 (veepoo-measure/index.tsx)
  ↓ navigateTo
原生分包页面 (pkg-veepoo/index.js + index.wxml)
  ↓ require('./libs/veepoo-sdk')
Veepoo SDK (veepoo-sdk.js)
  ↓ wx.* BLE API
微信蓝牙底层

为什么用原生分包而非 Taro

  1. SDK 是纯 JS372KB Webpack CommonJS2不兼容 Taro 编译流程
  2. SDK 使用全局变量 veepooBle/veepooFeature/veepooLogger,需要 require() 直接加载
  3. 微信小程序 JS 引擎不支持 ES2020 语法(???.),原生页面可精确控制语法
  4. 分包独立,不影响主包体积

构建集成

// config/index.ts — mini.copy.patterns
{ from: 'vendor/veepoo-sdk/libs/vp_sdk/index.js', to: 'dist/pkg-veepoo/libs/veepoo-sdk.js' },
{ from: 'native/pkg-veepoo/', to: 'dist/pkg-veepoo/', ignore: ['*.ts'] },

注意dev:weapp 的 watch 模式不监听 native/ 目录变化,修改原生页面后需清除 dist 重建:

rm -rf apps/miniprogram/dist/pkg-veepoo
pnpm run build:weapp  # 或 pnpm run dev:weapp

正确对接流程(已验证)

1. 页面加载onLoad

onLoad: function () {
  this._eventChannel = this.getOpenerEventChannel();
  // ❌ 不要在这里注册 veepooWeiXinSDKNotifyMonitorValueChange
  //    该函数内部会调用 wx.notifyBLECharacteristicValueChange
  //    此时蓝牙适配器未初始化 → 返回 "not init" 错误
}

2. 扫描

veepooBle.veepooWeiXinSDKStartScanDeviceAndReceiveScanningDevice(function (res) {
  var name = (device.localName || device.name || '').toUpperCase();
  // 匹配条件要放宽M2 / VPM / VEEPOO
  if (name.indexOf('M2') !== -1 || name.indexOf('VPM') !== -1 || name.indexOf('VEEPOO') !== -1) {
    // 找到设备
  }
});

3. 停止扫描 → 连接

veepooBle.veepooWeiXinSDKStopSearchBleManager(function () {
  veepooBle.veepooWeiXinSDKBleConnectionServicesCharacteristicsNotifyManager(device, callback);
});

4. 连接回调(关键!)

连接回调触发 4 次,每个阶段一次:

# 回调内容 含义
1 {errno:0, errMsg:"createBLEConnection:ok"} BLE TCP 连接建立
2 [{uuid:...}, ...] 服务发现完成
3 {characteristics:[...], errno:0} 特征值发现完成
4 {connection:true, deviceId:"..."} 特征值订阅完成,通道就绪

只响应第 4 次 connection:true

veepooBle.veepooWeiXinSDKBleConnectionServicesCharacteristicsNotifyManager(device, function (result) {
  // ❌ 不要用 errno===0 匹配!第 1 次回调就满足,但此时订阅未完成
  // ✅ 只匹配 connection:true第 4 次回调)
  if (result.connection === true) {
    // 此时 BLE 通道完全就绪
  }
});

5. 注册数据监听器(在 connection:true 回调内)

if (result.connection === true) {
  // ✅ 此时蓝牙适配器已初始化 + 连接已建立 + 特征值已订阅
  veepooBle.veepooWeiXinSDKNotifyMonitorValueChange(function (data) {
    // data.type 对应不同事件1=认证, 2=电量, 6=体温, 18=血压, 31=血氧, 51=心率, 58=压力
    handleSdkEvent(data);
  });

  // 同时注册连接状态变化监听
  veepooBle.veepooWeiXinSDKBLEConnectionStateChangeManager(function (res) {
    if (!res.connected) { /* 断开处理 */ }
  });
}

6. 认证(连接就绪后延迟 500ms

setTimeout(function () {
  veepooFeature.veepooBlePasswordCheckManager();
}, 500);

7. 认证结果判断(关键!)

// SDK 认证回调结构:
// {
//   type: 1,
//   content: {
//     VPDevicepassword: "0000",                    ← 设备密码原始值
//     VPDeviceAck: "successfulVerification",        ← ✅ 认证结果
//     VPDeviceVersion: "01.63.01.00-7466",
//     VPDeviceMAC: "BC:92:DC:9F:CA:6A",
//     ...
//   }
// }

// ❌ 错误:检查 VPDevicepassword值是 "0000",永远不匹配)
if (content.VPDevicepassword === 'successfulVerification') { ... }

// ✅ 正确:检查 VPDeviceAck
if (content.VPDeviceAck === 'successfulVerification' ||
    content.VPDeviceAck === 'passTheVerification') {
  // 认证成功
}

VPDeviceAck 可能的值

  • successfulVerification — 密码和时间校验成功
  • passTheVerification — 核验通过
  • verifyNotPass — 核验不通过
  • setupFailed — 设置不成功

8. Storage 轮询兜底

SDK 会写入 deviceChipStatus 到 Storage可能是布尔值 true 而非字符串

var status = wx.getStorageSync('deviceChipStatus');
// ✅ 同时匹配字符串和布尔值
if (status === 'successfulVerification' || status === 'passTheVerification' || status === true) {
  // 认证成功
}

完整流程图

onLoad → 扫描 → 找到M2 → 停止扫描
  ↓
连接(veepooWeiXinSDKBleConnectionServicesCharacteristicsNotifyManager)
  → 回调1(errno:0) → 忽略
  → 回调2(services) → 忽略
  → 回调3(characteristics) → 忽略
  → 回调4(connection:true) →
      ① 注册数据监听器(veepooWeiXinSDKNotifyMonitorValueChange)
      ② 注册连接状态监听器
      ③ 延迟500ms → 调用认证(veepooBlePasswordCheckManager)
      ④ 启动 Storage 轮询(deviceChipStatus) + 8s 超时
  ↓
数据监听器收到 type=1 事件 → 检查 VPDeviceAck === "successfulVerification"
  ↓
认证成功 → 设备就绪 → 可开始测量

踩坑清单

# 问题 根因 解决方案
1 原生页面 ?? 报 SyntaxError 微信小程序 JS 引擎不支持 ES2020 != null 三元表达式替代
2 veepoo-measure 白屏 useRef is not defined TSX import 未解构 useRef import React, { useRef } from 'react'
3 扫描不到 M2 设备 过滤条件只匹配 M2,设备可能广播其他名 放宽匹配 M2/VPM/VEEPOO
4 认证超时 — 回调匹配过早 errno:0 在第 1 次回调就匹配 只匹配 connection:true
5 认证超时 — 监听器注册过早 onLoad 时适配器未初始化 → not init 改到 connection:true 后注册
6 认证超时 — 字段检查错误 检查 VPDevicepassword(值="0000")而非 VPDeviceAck 改为检查 VPDeviceAck
7 deviceChipStatus 轮询失败 SDK 写入布尔值 true 而非字符串 同时匹配字符串和布尔值
8 vibrateShort promise rejection DevTools 不支持 type 参数try/catch 无法捕获异步 rejection 改用 .catch()
9 dist 不更新 dev:weapp watch 不监听 native/ 目录 修改原生页面后需 rm -rf dist/pkg-veepoo 重建

dev:weapp 注意事项

  • 原生页面修改后不会自动热更新,需手动清除 dist 重建
  • DevTools 日志需要选中正确的页面上下文(pkg-veepoo)才能看到原生页面日志
  • 关闭 DevTools 后重新打开,确保加载最新的 dist 文件