当你的爱犬在公园里欢快地奔跑时,作为主人的你是否曾担心它会突然消失?这正是我们团队开发宠物定位器的初衷。不同于普通的蓝牙开发教程,本文将从一个真实项目的角度,深入剖析UniApp蓝牙开发中的那些"坑"——特别是当你需要同时兼顾iOS和Android平台时,遇到的问题往往比想象中复杂得多。
我们的宠物定位器项目需要实现以下核心功能:通过蓝牙信号实时监测宠物项圈与手机之间的距离,当距离超出安全范围时自动提醒主人。听起来简单?实际操作中我们遇到了三大挑战:
提示:在宠物定位场景中,2-3米的精度已经足够,过分追求厘米级精度反而会增加不必要的复杂度
很多教程会告诉你调用uni.openBluetoothAdapter()就完事了,但真实项目中远不止如此。我们在初始化阶段踩过的坑包括:
javascript复制// 完整的初始化流程应该包含状态检测
async initBluetooth() {
try {
await this.openBluetoothAdapter();
const state = await this.getBluetoothAdapterState();
if (!state.discovering) {
await this.startDiscovery();
}
} catch (error) {
this.handleBluetoothError(error);
}
}
关键点分析:
我们总结的错误处理优先级:
| 错误类型 | 处理方式 | 用户提示 |
|---|---|---|
| 蓝牙未开启 | 引导开启 | "请打开手机蓝牙功能" |
| 位置权限缺失 | 跳转设置 | "需要位置权限来扫描设备" |
| 硬件不支持 | 禁用功能 | "您的设备不支持蓝牙4.0" |
| 其他错误 | 重试机制 | "蓝牙服务暂时不可用" |
宠物项圈的蓝牙设备通常会广播特定的服务UUID或设备名称。我们的筛选逻辑经历了三次迭代:
javascript复制function basicFilter(devices) {
return devices.filter(device =>
device.name && device.name.includes('PET_TAG')
);
}
简单的RSSI绝对值并不可靠,我们采用了滑动窗口算法:
javascript复制class RssiFilter {
constructor(windowSize = 5) {
this.window = [];
this.size = windowSize;
}
add(rssi) {
this.window.push(rssi);
if (this.window.length > this.size) {
this.window.shift();
}
return this.avg();
}
avg() {
return this.window.reduce((a,b) => a + b, 0) / this.window.length;
}
}
针对iOS和Android的不同表现,我们最终采用的兼容方案:
Android设备:
iOS设备:
通过RSSI估算距离是宠物定位的核心,但信号强度受多种因素影响:
环境干扰因素:
我们测试了三种距离计算公式的准确度:
| 模型 | 公式 | 适用场景 | 误差范围 |
|---|---|---|---|
| 自由空间 | d = 10^((A-RSSI)/(10*n)) | 空旷环境 | ±1.5m |
| 对数正态 | 考虑环境因子 | 室内 | ±0.8m |
| 机器学习 | 基于历史数据训练 | 固定环境 | ±0.5m |
实际项目中,我们选择了折衷的对数正态模型,在代码中这样实现:
javascript复制function calculateDistance(rssi, txPower = -59, envFactor = 2.5) {
if (rssi >= 0) return Number.POSITIVE_INFINITY;
const ratio = rssi * 1.0 / txPower;
return Math.pow(10, (txPower - rssi) / (10 * envFactor));
}
持续蓝牙扫描会显著增加耗电,我们通过以下方式优化:
javascript复制const deviceCache = new Map();
function updateCache(device) {
const cached = deviceCache.get(device.id);
if (!cached || cached.rssi < device.rssi) {
deviceCache.set(device.id, {
...device,
timestamp: Date.now()
});
}
// 清理过期缓存
for (let [id, entry] of deviceCache) {
if (Date.now() - entry.timestamp > 30000) {
deviceCache.delete(id);
}
}
}
由于平台限制,我们最终采用的方案:
经过三个月的开发和迭代,我们的宠物定位器在测试环境中达到了92%的准确率。几个关键收获:
在真实项目中,处理异常情况的代码往往比正常流程多3-5倍。比如我们遇到过一个特殊案例:某款国产手机在省电模式下会随机改变蓝牙MAC地址,导致设备"丢失"。最终通过增加设备特征匹配逻辑解决了这个问题。