引入
import {
BluetoothBumpDeps,
BluetoothDeviceInfo,
BluetoothBumpError,
BluetoothBumpPayload,
BluetoothBumpOptions,
ShouldTriggerBumpParams,
PeerRecord,
WxBluetoothAdapter,
DEFAULT_SERVICE_UUID,
DEFAULT_CHARACTERISTIC_UUID,
DEFAULT_RSSI_THRESHOLD,
DEFAULT_COOLDOWN_MS,
DEFAULT_LINGER_BEFORE_STOP_MS,
DEFAULT_POLL_INTERVAL_MS,
DEFAULT_PRIVACY_CONTENT,
DEFAULT_PEER_TTL_MS,
DEFAULT_ADVERTISE_UPDATE_THROTTLE_MS,
EMPTY_PEER_ID,
PAYLOAD_SEPARATOR,
TEMP_ID_LENGTH,
BUMP_NAME_PREFIX,
genTempId,
str2ArrayBuffer,
arrayBuffer2Hex,
reverseHexBytes,
matchesService,
shouldTriggerBump,
encodePayload,
encodeBumpName,
parseBumpName,
parsePayloadString,
parsePayload,
pickBestPeer,
pruneExpiredPeers,
arrayBufferToUtf8,
padOrTrim,
BluetoothBumpMode
} from 't-comm';
// 不支持 tree-shaking 的项目
import {
BluetoothBumpDeps,
BluetoothDeviceInfo,
BluetoothBumpError,
BluetoothBumpPayload,
BluetoothBumpOptions,
ShouldTriggerBumpParams,
PeerRecord,
WxBluetoothAdapter,
DEFAULT_SERVICE_UUID,
DEFAULT_CHARACTERISTIC_UUID,
DEFAULT_RSSI_THRESHOLD,
DEFAULT_COOLDOWN_MS,
DEFAULT_LINGER_BEFORE_STOP_MS,
DEFAULT_POLL_INTERVAL_MS,
DEFAULT_PRIVACY_CONTENT,
DEFAULT_PEER_TTL_MS,
DEFAULT_ADVERTISE_UPDATE_THROTTLE_MS,
EMPTY_PEER_ID,
PAYLOAD_SEPARATOR,
TEMP_ID_LENGTH,
BUMP_NAME_PREFIX,
genTempId,
str2ArrayBuffer,
arrayBuffer2Hex,
reverseHexBytes,
matchesService,
shouldTriggerBump,
encodePayload,
encodeBumpName,
parseBumpName,
parsePayloadString,
parsePayload,
pickBestPeer,
pruneExpiredPeers,
arrayBufferToUtf8,
padOrTrim,
BluetoothBumpMode
} from 't-comm/lib/bluetooth-bump/index';
// 只支持 ESM 的项目
import {
BluetoothBumpDeps,
BluetoothDeviceInfo,
BluetoothBumpError,
BluetoothBumpPayload,
BluetoothBumpOptions,
ShouldTriggerBumpParams,
PeerRecord,
WxBluetoothAdapter,
DEFAULT_SERVICE_UUID,
DEFAULT_CHARACTERISTIC_UUID,
DEFAULT_RSSI_THRESHOLD,
DEFAULT_COOLDOWN_MS,
DEFAULT_LINGER_BEFORE_STOP_MS,
DEFAULT_POLL_INTERVAL_MS,
DEFAULT_PRIVACY_CONTENT,
DEFAULT_PEER_TTL_MS,
DEFAULT_ADVERTISE_UPDATE_THROTTLE_MS,
EMPTY_PEER_ID,
PAYLOAD_SEPARATOR,
TEMP_ID_LENGTH,
BUMP_NAME_PREFIX,
genTempId,
str2ArrayBuffer,
arrayBuffer2Hex,
reverseHexBytes,
matchesService,
shouldTriggerBump,
encodePayload,
encodeBumpName,
parseBumpName,
parsePayloadString,
parsePayload,
pickBestPeer,
pruneExpiredPeers,
arrayBufferToUtf8,
padOrTrim,
BluetoothBumpMode
} from 't-comm/es/bluetooth-bump/index';BluetoothBumpDeps
描述:主类的额外依赖(用于测试时注入假时钟、假 timer、假 adapter)
参数:
BluetoothDeviceInfo
描述:蓝牙"碰一碰"对外类型定义
参数:
BluetoothBumpError
描述:启动失败时通过 onError 抛出的错误信息
参数:
BluetoothBumpPayload
描述:广播载荷(mutual 模式):固定长度 13 字节,myTempId|seenPeerId
参数:
BluetoothBumpPayload.myTempId:string.seenPeerId:string
bluetoothBumpPayload.myTempId : string
发送端自己的临时 ID(6 位大写)
Kind: instance property of BluetoothBumpPayload
bluetoothBumpPayload.seenPeerId : string
发送端当前"看到的对方 ID",未看到时为 '------'
Kind: instance property of BluetoothBumpPayload
BluetoothBumpOptions
描述:BluetoothBump 构造选项
参数:
BluetoothBumpOptions.serviceUuid:string.characteristicUuid:string.rssiThreshold:number.cooldownMs:number.lingerBeforeStopMs:number.pollIntervalMs:number.privacyContent:string.mode:BluetoothBumpMode.peerTtlMs:number.advertiseUpdateThrottleMs:number.onBump:function.onError:function.onLog:function.onDeviceFound:function
bluetoothBumpOptions.serviceUuid : string
服务 UUID,两端必须一致
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.characteristicUuid : string
特征 UUID(仅外围模式使用)
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.rssiThreshold : number
RSSI 阈值,超过此值视为"碰到了"
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.cooldownMs : number
同一设备的去重冷却时间
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.lingerBeforeStopMs : number
成功触发后保持广播的时长(让对方也能扫到自己)
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.pollIntervalMs : number
iOS 兜底轮询间隔
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.privacyContent : string
隐私协议弹窗内容(不传用默认文案)
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.mode : BluetoothBumpMode
匹配模式,默认 'simple'(保持向后兼容)。 选 'mutual' 开启前端自撮合(双向互认后才触发 onBump)。
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.peerTtlMs : number
mutual 模式:候选 peer 信息的有效期(毫秒),过期则从候选池移除
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.advertiseUpdateThrottleMs : number
mutual 模式:更新自己广播里 seenPeerId 的最小间隔(毫秒),防抖
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.onBump : function
业务回调:碰到对方时触发
- peerDeviceId:扫描层的设备地址(iOS 是本机视角的 UUID,Android 是 MAC)。 ⚠️ 这个值是"扫描者本地"视角的,A 拿到的对方 deviceId 与 B 自己的 deviceId 不一定相同, 不能用它跟对方的 myTempId 直接对比。
- peerTempId:对方写在广播 payload 里的 myTempId(6 位字符串)。 这个值是"对方应用层产生的",A 看到的 peerTempId 与 B 的 myTempId 一定一致, 适合两台手机做配对核对("我方 ID" vs "对方 ID")。 若对方广播解析失败则为空字符串。
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.onError : function
业务回调:启动失败时触发
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.onLog : function
业务回调:日志/状态变化(用于打日志或 UI 更新)
Kind: instance property of BluetoothBumpOptions
Optional:
bluetoothBumpOptions.onDeviceFound : function
业务回调:每次扫到设备(不论是否碰到)时触发,用于调试/UI 展示
Kind: instance property of BluetoothBumpOptions
Optional:
ShouldTriggerBumpParams
描述:触发碰一碰的判定参数(纯函数 shouldTriggerBump 使用)
参数:
PeerRecord
描述:候选 peer 的内存记录
参数:
PeerRecord.seenPeerId:string.lastSeen:number.dev:BluetoothDeviceInfo
peerRecord.seenPeerId : string
对方广播里携带的"它看到的对方 ID"(用于判断是否是双向互认)
Kind: instance property of PeerRecord
peerRecord.lastSeen : number
最近一次见到的时间戳
Kind: instance property of PeerRecord
peerRecord.dev : BluetoothDeviceInfo
对应的原始设备,便于回传给业务方
Kind: instance property of PeerRecord
WxBluetoothAdapter
描述:微信蓝牙能力适配器接口(用于依赖注入,便于测试)
参数:
WxBluetoothAdapter.isAvailable:boolean.detectPlatform:string.ensurePrivacyAuthorized:Promise.<void>.openAdapter:Promise.<OpenAdapterResult>.startAdvertising:Promise.<object>.updateAdvertisedValue:Promise.<void>.startDiscovery:Promise.<void>.onDeviceFound:void.onAdapterStateChange:void.getDevices:Promise.<object>.stopDiscovery:void
wxBluetoothAdapter.isAvailable : boolean
当前环境是否具备最低限度的蓝牙 API
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.detectPlatform : string
检测平台(ios / android / devtools / unknown ...)
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.ensurePrivacyAuthorized : Promise.<void>
触发隐私授权弹窗并等待用户同意(不支持时直接 resolve)
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.openAdapter : Promise.<OpenAdapterResult>
打开蓝牙适配器;iOS 上分别打开 central + peripheral,并返回是否需跳过广播
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.startAdvertising : Promise.<object>
创建外围设备并开始广播
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.updateAdvertisedValue : Promise.<void>
更新正在广播的 payload(mutual 模式用)。 实现:stopAdvertising → 重新 addService(新 value)→ startAdvertising。 失败时 reject,调用方需要自己决定是否回退。
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.startDiscovery : Promise.<void>
开始扫描:iOS 不传 services(系统重新包装广播包后会扫不到)
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.onDeviceFound : void
注册扫描回调
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.onAdapterStateChange : void
注册适配器状态变化回调
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.getDevices : Promise.<object>
iOS 兜底轮询用
Kind: instance property of WxBluetoothAdapter
wxBluetoothAdapter.stopDiscovery : void
停止扫描 / 停止广播 / 关闭适配器(任一失败都安全吞掉)
Kind: instance property of WxBluetoothAdapter
DEFAULT_SERVICE_UUID
描述:自定义服务 UUID(两端必须一致,作为"同一个小游戏"的识别标记)
参数:
DEFAULT_CHARACTERISTIC_UUID
描述:自定义特征 UUID(创建外围设备时需要)
参数:
DEFAULT_RSSI_THRESHOLD
描述:触发"碰一碰"的 RSSI 阈值(dBm),越接近 0 表示距离越近
参数:
DEFAULT_COOLDOWN_MS
描述:同一台设备多次触发的去重时间(毫秒)
参数:
DEFAULT_LINGER_BEFORE_STOP_MS
描述:触发成功后保持广播的时长(毫秒),让对方也能扫到自己
参数:
DEFAULT_POLL_INTERVAL_MS
描述:iOS 兜底轮询间隔(毫秒)
参数:
DEFAULT_PRIVACY_CONTENT
描述:默认隐私协议弹窗内容
参数:
DEFAULT_PEER_TTL_MS
描述:mutual 模式:候选 peer 的 TTL(毫秒),超过未再见即从候选池移除
参数:
DEFAULT_ADVERTISE_UPDATE_THROTTLE_MS
描述:mutual 模式:更新自己广播里 seenPeerId 的最小间隔(毫秒)
参数:
EMPTY_PEER_ID
描述:mutual 模式:广播 payload 占位符(未看到对方时)
参数:
PAYLOAD_SEPARATOR
描述:mutual 模式:广播 payload 分隔符
参数:
TEMP_ID_LENGTH
描述:临时 ID 长度(genTempId 生成 6 位)
参数:
BUMP_NAME_PREFIX
描述:广播设备名前缀(iOS Peripheral 唯一能下发的自定义字段就是 localName) 完整格式: BUMP_<myTempId> 或 BUMP_<myTempId>_<seenPeerId> 原理:iOS CoreBluetooth 不允许 Peripheral 在广播包里塞 ServiceData, 只允许 localName + serviceUUIDs。所以 iOS↔iOS 必须靠 localName 传 myTempId。 Android 同样支持 localName,所以这套方案跨平台一致。
参数:
genTempId()
描述:生成 6 位随机大写临时 ID(写到广播特征值里)
参数:
str2ArrayBuffer()
描述:把字符串编码为 ArrayBuffer,用于写入特征值
参数:
arrayBuffer2Hex()
描述:ArrayBuffer 转十六进制大写字符串
参数:
reverseHexBytes()
描述:反转十六进制字符串的字节序(小端 ↔ 大端)
参数:
matchesService()
描述:判断扫到的设备是否携带我们的 service iOS 上 startBluetoothDevicesDiscovery 不传 services 时收到的设备都需要手动过滤。 依次检查:advertisServiceUUIDs / serviceData / advertisData / 设备名前缀(BUMP_)。 ⚠️ iOS↔iOS 时前 3 项几乎都拿不到,必须靠设备名前缀做最终兜底。
参数:
shouldTriggerBump()
描述:判断这次扫描结果是否应该触发"碰一碰" 条件:
- - RSSI 不低于阈值(够近) - 距离上次同设备触发已超过冷却时间(避免重复)
参数:
encodePayload()
描述:把 myTempId / seenPeerId 组装为广播 payload 字符串。 固定长度,便于解析:${myTempId}|${seenPeerId} → 13 字节。
- myTempId 如果不足 TEMP_ID_LENGTH 位会自动补 '-'(防御性处理)
- seenPeerId 为空时填占位符 '------'
参数:
encodeBumpName()
描述:把 payload 编码进设备名(iOS Peripheral 唯一可控的广播字段)。 BUMP_<myTempId>_<seenPeerId> → 例 BUMP_ABC123_------(19 字符) 不少机型对 localName 长度有限制(iOS Peripheral 推荐 ≤ 28 字节),这里 19 字符够用。
参数:
parseBumpName()
描述:解析设备名形如 BUMP_ABC123_XYZ789 → { myTempId, seenPeerId }。 仅需 myTempId 时(旧格式 BUMP_ABC123)也兼容,seenPeerId 返回空串。
参数:
parsePayloadString()
描述:解析广播 payload 字符串 → { myTempId, seenPeerId } 解析失败返回 null(payload 不是本协议)。 seenPeerId 为占位符 '------' 时返回空字符串,方便上层 if (seenPeerId) 判断。
参数:
parsePayload()
描述:从扫描到的设备里提取 mutual 协议 payload。 解析顺序(按"iOS 上能拿到的可能性"由高到低):
- - 设备名 / localName 前缀 `BUMP_` —— iOS↔iOS 唯一可靠通道 - serviceData[serviceUuid] —— Android 标准方案 - advertisData 整段 —— 部分机型把 payload 塞这里 - 设备名按旧格式 `myTempId|seenPeerId` 解析(向后兼容)
参数:
pickBestPeer()
描述:从候选池里挑选"信号最强且在 TTL 内"的 peer(用于决定广播里要"点名"谁)
参数:
pruneExpiredPeers()
描述:清理候选池里过期的 peer(就地修改)
参数:
arrayBufferToUtf8()
描述:ArrayBuffer 转 UTF-8 字符串(失败返回空字符串)
参数:
padOrTrim()
描述:定长裁剪/补齐(补 '-')
参数:
BluetoothBumpMode
描述:匹配模式:
- 'simple' :默认行为。扫到对方且 RSSI 达标即触发(单向发现,简单快速)。
- 'mutual' :前端自撮合。双向互认后才触发: 我广播里带"我看到的对方 ID",对方广播里也带"它看到的对方 ID"; 当双方广播里携带的 peerId 都指向对方时,才算配对成功。
参数: