鸿蒙5蓝牙防丢器应用开发指南 原创

进修的泡芙
发布于 2025-6-20 14:33
浏览
0收藏

鸿蒙5蓝牙防丢器应用开发指南

一、项目概述

本文基于HarmonyOS 5的蓝牙近距离感知能力和分布式技术,开发一款蓝牙防丢器应用,借鉴《鸿蒙跨端U同步》中游戏多设备同步的技术原理,实现设备间的距离监测、分离报警和多设备协同定位功能。该系统能够在绑定设备超出安全距离时触发报警,并通过分布式能力实现多设备间的状态同步。

二、系统架构

±--------------------+ ±--------------------+ ±--------------------+
主控手机设备 <-----> 分布式数据总线 <-----> 蓝牙防丢器设备
(Master Phone) (Distributed Bus) (Bluetooth Tracker)
±---------±---------+ ±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+ ±---------v----------+
报警逻辑引擎 状态同步服务 距离监测模块
(Alert Engine) (Sync Service) (Distance Monitor)

±--------------------+ ±--------------------+ ±--------------------+

三、核心代码实现
设备数据模型

// src/main/ets/model/TrackerDeviceModel.ts
export class TrackerDevice {
deviceId: string; // 设备唯一标识
name: string; // 设备名称
lastConnected: number; // 最后连接时间
lastRssi: number; // 最后信号强度
safeDistance: number; // 安全距离(米)
isConnected: boolean; // 是否连接
isAlerting: boolean; // 是否正在报警
batteryLevel: number; // 电池电量(0-100)
position?: { // 最后已知位置(可选)
latitude: number;
longitude: number;
};

constructor(deviceId: string, name: string) {
this.deviceId = deviceId;
this.name = name;
this.lastConnected = Date.now();
this.lastRssi = 0;
this.safeDistance = 10;
this.isConnected = false;
this.isAlerting = false;
this.batteryLevel = 100;
updateRssi(rssi: number): void {

this.lastRssi = rssi;
this.lastConnected = Date.now();

calculateDistance(): number {

// 根据RSSI估算距离(简化版)
if (this.lastRssi >= 0) return Infinity;
const txPower = -59; // 1米处的RSSI值
return Math.pow(10, (txPower - this.lastRssi) / (10 * 2));

toJson(): string {

return JSON.stringify({
  deviceId: this.deviceId,
  name: this.name,
  lastConnected: this.lastConnected,
  lastRssi: this.lastRssi,
  safeDistance: this.safeDistance,
  isConnected: this.isConnected,
  isAlerting: this.isAlerting,
  batteryLevel: this.batteryLevel,
  position: this.position
});

static fromJson(jsonStr: string): TrackerDevice {

const json = JSON.parse(jsonStr);
const device = new TrackerDevice(json.deviceId, json.name);
device.lastConnected = json.lastConnected;
device.lastRssi = json.lastRssi;
device.safeDistance = json.safeDistance;
device.isConnected = json.isConnected;
device.isAlerting = json.isAlerting;
device.batteryLevel = json.batteryLevel;
device.position = json.position;
return device;

}

分布式同步服务

// src/main/ets/service/DistributedSyncService.ts
import { distributedData } from ‘@ohos.data.distributedData’;
import { BusinessError } from ‘@ohos.base’;
import { TrackerDevice } from ‘…/model/TrackerDeviceModel’;
import { deviceManager } from ‘@ohos.distributedDeviceManager’;

export class DistributedSyncService {
private static instance: DistributedSyncService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;
private readonly STORE_ID = ‘tracker_store’;
private readonly DEVICE_KEY_PREFIX = ‘tracker_’;
private subscribers: ((data: TrackerDevice) => void)[] = [];

private constructor() {
this.initDistributedData();
public static getInstance(): DistributedSyncService {

if (!DistributedSyncService.instance) {
  DistributedSyncService.instance = new DistributedSyncService();

return DistributedSyncService.instance;

private initDistributedData(): void {

const config: distributedData.KVManagerConfig = {
  bundleName: 'com.example.tracker',
  userInfo: {
    userId: '0',
    userType: distributedData.UserType.SAME_USER_ID

};

try {
  distributedData.createKVManager(config, (err: BusinessError, manager: distributedData.KVManager) => {
    if (err) {
      console.error(Failed to create KVManager. Code: {err.code}, message: {err.message});
      return;

this.kvManager = manager;

    const options: distributedData.Options = {
      createIfMissing: true,
      encrypt: true,
      backup: false,
      autoSync: true,
      kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
      schema: '',
      securityLevel: distributedData.SecurityLevel.S2
    };

    this.kvManager.getKVStore(this.STORE_ID, options, (err: BusinessError, store: distributedData.KVStore) => {
      if (err) {
        console.error(Failed to get KVStore. Code: {err.code}, message: {err.message});
        return;

this.kvStore = store;

      this.registerDataListener();
    });
  });

catch (e) {

  console.error(An unexpected error occurred. Code: {e.code}, message: {e.message});

}

private registerDataListener(): void {
try {
this.kvStore.on(‘dataChange’, distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data: distributedData.ChangeData) => {
if (data.key.startsWith(this.DEVICE_KEY_PREFIX)) {
const device = TrackerDevice.fromJson(data.value.value as string);
this.notifySubscribers(device);
});

catch (e) {

  console.error(Failed to register data listener. Code: {e.code}, message: {e.message});

}

public subscribe(callback: (data: TrackerDevice) => void): void {
this.subscribers.push(callback);
public unsubscribe(callback: (data: TrackerDevice) => void): void {

this.subscribers = this.subscribers.filter(sub => sub !== callback);

private notifySubscribers(data: TrackerDevice): void {

this.subscribers.forEach(callback => callback(data));

public syncDevice(device: TrackerDevice): void {

if (!this.kvStore) {
  console.error('KVStore is not initialized');
  return;

try {

  const key = this.DEVICE_KEY_PREFIX + device.deviceId;
  this.kvStore.put(key, device.toJson(), (err: BusinessError) => {
    if (err) {
      console.error(Failed to put device. Code: {err.code}, message: {err.message});

});

catch (e) {

  console.error(An unexpected error occurred. Code: {e.code}, message: {e.message});

}

public async getTrackedDevices(): Promise<TrackerDevice[]> {
return new Promise((resolve) => {
if (!this.kvStore) {
resolve([]);
return;
try {

    const query: distributedData.Query = {
      prefixKey: this.DEVICE_KEY_PREFIX
    };

    this.kvStore.getEntries(query, (err: BusinessError, entries: distributedData.Entry[]) => {
      if (err) {
        console.error(Failed to get entries. Code: {err.code}, message: {err.message});
        resolve([]);
        return;

const devices = entries.map(entry =>

        TrackerDevice.fromJson(entry.value.value as string)
      );
      resolve(devices);
    });

catch (e) {

    console.error(An unexpected error occurred. Code: {e.code}, message: {e.message});
    resolve([]);

});

}

蓝牙距离监测服务

// src/main/ets/service/BluetoothTrackerService.ts
import { bluetooth } from ‘@ohos.bluetooth’;
import { BusinessError } from ‘@ohos.base’;
import { TrackerDevice } from ‘…/model/TrackerDeviceModel’;
import { DistributedSyncService } from ‘./DistributedSyncService’;
import { geolocation } from ‘@ohos.geolocation’;

export class BluetoothTrackerService {
private static instance: BluetoothTrackerService;
private syncService = DistributedSyncService.getInstance();
private trackedDevices: Map<string, TrackerDevice> = new Map();
private scanInterval: number = 0;
private alertTimeout: number = 0;

private constructor() {
this.initBluetooth();
public static getInstance(): BluetoothTrackerService {

if (!BluetoothTrackerService.instance) {
  BluetoothTrackerService.instance = new BluetoothTrackerService();

return BluetoothTrackerService.instance;

private initBluetooth(): void {

try {
  bluetooth.enableBluetooth();
  
  bluetooth.on('bluetoothStateChange', (state: number) => {
    console.log(Bluetooth state changed: ${state});
  });

  bluetooth.on('deviceFind', (device: bluetooth.BluetoothDevice) => {
    if (this.trackedDevices.has(device.deviceId)) {
      this.updateDeviceRssi(device.deviceId, device.rssi);

});

catch (e) {

  console.error(Failed to init Bluetooth. Code: {e.code}, message: {e.message});

}

public startTracking(device: TrackerDevice, interval: number = 5000): void {
this.trackedDevices.set(device.deviceId, device);
this.syncService.syncDevice(device);

if (!this.scanInterval) {
  this.scanInterval = setInterval(() => {
    this.performScan();
  }, interval);

}

public stopTracking(deviceId: string): void {
this.trackedDevices.delete(deviceId);

if (this.trackedDevices.size === 0 && this.scanInterval) {
  clearInterval(this.scanInterval);
  this.scanInterval = 0;

}

private performScan(): void {
try {
bluetooth.startBluetoothDiscovery();

  // 10秒后停止扫描
  setTimeout(() => {
    bluetooth.stopBluetoothDiscovery();
    this.checkDevicesDistance();
  }, 10000);

catch (e) {

  console.error(Failed to perform scan. Code: {e.code}, message: {e.message});

}

private updateDeviceRssi(deviceId: string, rssi: number): void {
const device = this.trackedDevices.get(deviceId);
if (device) {
device.updateRssi(rssi);
device.isConnected = true;
this.syncService.syncDevice(device);
}

private async checkDevicesDistance(): Promise<void> {
for (const [deviceId, device] of this.trackedDevices) {
const distance = device.calculateDistance();

  if (distance > device.safeDistance) {
    device.isAlerting = true;
    this.triggerAlert(device);

else {

    device.isAlerting = false;

// 更新设备位置

  await this.updateDevicePosition(device);
  this.syncService.syncDevice(device);

}

private async updateDevicePosition(device: TrackerDevice): Promise<void> {
try {
const location = await geolocation.getCurrentLocation();
device.position = {
latitude: location.latitude,
longitude: location.longitude
};
catch (e) {

  console.error(Failed to get location. Code: {e.code}, message: {e.message});

}

private triggerAlert(device: TrackerDevice): void {
// 振动提醒
vibrator.vibrate({
duration: 1000,
count: 3
}, (err: BusinessError) => {
if (err) {
console.error(Failed to vibrate. Code: {err.code}, message: {err.message});
});

// 显示通知
notification.show({
  content: ${device.name} 超出安全距离!,
  title: '防丢器报警'
});

// 5分钟后再次检查
if (this.alertTimeout) {
  clearTimeout(this.alertTimeout);

this.alertTimeout = setTimeout(() => {

  this.checkDevicesDistance();
}, 300000) as unknown as number;

public async getTrackedDevices(): Promise<TrackerDevice[]> {

return Array.from(this.trackedDevices.values());

}

主控设备界面

// src/main/ets/pages/MasterView.ets
import { TrackerDevice } from ‘…/model/TrackerDeviceModel’;
import { BluetoothTrackerService } from ‘…/service/BluetoothTrackerService’;
import { DistributedSyncService } from ‘…/service/DistributedSyncService’;
import { bluetooth } from ‘@ohos.bluetooth’;

@Entry
@Component
struct MasterView {
@State devices: TrackerDevice[] = [];
@State scannedDevices: bluetooth.BluetoothDevice[] = [];
@State isScanning: boolean = false;
@State selectedDevice: TrackerDevice | null = null;
private trackerService = BluetoothTrackerService.getInstance();
private syncService = DistributedSyncService.getInstance();

aboutToAppear(): void {
this.syncService.subscribe(this.handleDeviceUpdate.bind(this));
this.loadTrackedDevices();
aboutToDisappear(): void {

this.syncService.unsubscribe(this.handleDeviceUpdate.bind(this));

private handleDeviceUpdate(data: TrackerDevice): void {

const index = this.devices.findIndex(d => d.deviceId === data.deviceId);
if (index >= 0) {
  this.devices[index] = data;

else {

  this.devices.push(data);

this.devices = […this.devices];

private async loadTrackedDevices(): Promise<void> {

const tracked = await this.trackerService.getTrackedDevices();
const synced = await this.syncService.getAllDevices();

// 合并设备列表
const allDevices = [...tracked, ...synced];
const uniqueDevices = Array.from(new Map(allDevices.map(d => [d.deviceId, d])).values());

this.devices = uniqueDevices;

private async scanForDevices(): Promise<void> {

this.isScanning = true;
try {
  bluetooth.startBluetoothDiscovery();
  
  setTimeout(() => {
    bluetooth.stopBluetoothDiscovery();
    this.isScanning = false;
  }, 10000);

catch (e) {

  console.error(Failed to scan devices. Code: {e.code}, message: {e.message});
  this.isScanning = false;

}

private async connectDevice(device: bluetooth.BluetoothDevice): Promise<void> {
try {
await bluetooth.createBond(device.deviceId);

  const tracker = new TrackerDevice(device.deviceId, device.name || '防丢器');
  this.trackerService.startTracking(tracker);
  this.selectedDevice = tracker;

catch (e) {

  console.error(Failed to connect device. Code: {e.code}, message: {e.message});

}

private updateSafeDistance(distance: number): void {
if (this.selectedDevice) {
this.selectedDevice.safeDistance = distance;
this.trackerService.startTracking(this.selectedDevice);
}

private getDistanceColor(distance: number, safeDistance: number): ResourceColor {
const ratio = distance / safeDistance;
if (ratio > 1) return ‘#FF5252’; // 红色 - 超出安全距离
if (ratio > 0.7) return ‘#FF9800’; // 橙色 - 接近安全距离
return ‘#4CAF50’; // 绿色 - 安全范围内
build() {

Column() {
  // 设备扫描区域
  Row() {
    Text('蓝牙防丢器')
      .fontSize(24)
      .fontWeight(FontWeight.Bold)
    
    Button(this.isScanning ? '停止扫描' : '扫描设备')
      .margin({left: 20})
      .onClick(() => this.scanForDevices())

.width(‘100%’)

  .justifyContent(FlexAlign.Center)
  .margin({bottom: 20})

  // 设备列表
  List({ space: 10 }) {
    ForEach(this.devices, (device) => {
      ListItem() {
        Column() {
          Row() {
            Text(device.name)
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
            
            if (device.isAlerting) {
              Image('resources/alert.png')
                .width(20)
                .height(20)
                .margin({left: 10})

}

          Row() {
            const distance = device.calculateDistance();
            Text(${distance.toFixed(1)} 米)
              .fontColor(this.getDistanceColor(distance, device.safeDistance))
            
            Text(电量: ${device.batteryLevel}%)
              .fontSize(14)
              .margin({left: 20})

.margin({top: 5})

.width(‘100%’)

        .padding(10)
        .borderRadius(10)
        .backgroundColor(this.selectedDevice?.deviceId === device.deviceId ? '#E3F2FD' : '#FAFAFA')

.onClick(() => {

        this.selectedDevice = device;
      })
    })

.width(‘100%’)

  .layoutWeight(1)

  // 设备控制面板
  if (this.selectedDevice) {
    Column() {
      Text(this.selectedDevice.name)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      
      Row() {
        Text('安全距离:')
          .fontSize(16)
        
        Slider({
          value: this.selectedDevice.safeDistance,
          min: 1,
          max: 50,
          step: 1,
          style: SliderStyle.OutSet
        })
        .width(150)
        .margin({left: 10})
        .onChange(v => this.updateSafeDistance(v))
        
        Text(${this.selectedDevice.safeDistance} 米)
          .fontSize(14)
          .margin({left: 10})

.margin({top: 15})

      if (this.selectedDevice.position) {
        Text(最后位置: {this.selectedDevice.position.latitude.toFixed(4)}, {this.selectedDevice.position.longitude.toFixed(4)})
          .fontSize(14)
          .margin({top: 10})

Button(‘设为防丢目标’)

        .width('100%')
        .margin({top: 20})
        .onClick(() => {
          this.trackerService.startTracking(this.selectedDevice!);
        })

.width(‘100%’)

    .padding(15)
    .margin({top: 10})
    .borderRadius(10)
    .backgroundColor('#FFFFFF')
    .shadow({ radius: 5, color: '#E0E0E0', offsetX: 0, offsetY: 2 })

}

.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#F5F5F5')

}

防丢器设备界面

// src/main/ets/pages/TrackerView.ets
import { DistributedSyncService } from ‘…/service/DistributedSyncService’;
import { deviceManager } from ‘@ohos.distributedDeviceManager’;
import { bluetooth } from ‘@ohos.bluetooth’;

@Entry
@Component
struct TrackerView {
@State deviceName: string = ‘蓝牙防丢器’;
@State batteryLevel: number = 100;
@State isConnected: boolean = false;
@State isAlerting: boolean = false;
private syncService = DistributedSyncService.getInstance();

aboutToAppear(): void {
deviceManager.getLocalDeviceInfo((err, info) => {
if (!err) {
this.deviceName = info.deviceName;
const device = new TrackerDevice(info.deviceId, info.deviceName);
this.syncService.syncDevice(device);
});

// 模拟电池电量变化
setInterval(() => {
  this.batteryLevel = Math.max(0, this.batteryLevel - 1);
  if (this.batteryLevel <= 20 && !this.isAlerting) {
    this.isAlerting = true;
    this.triggerLowBatteryAlert();

else if (this.batteryLevel > 20) {

    this.isAlerting = false;

}, 60000); // 每分钟减少1%

private triggerLowBatteryAlert(): void {

// 防丢器自身的报警方式(如蜂鸣)
vibrator.vibrate({
  duration: 200,
  count: 5
});

build() {

Column() {
  Text(this.deviceName)
    .fontSize(24)
    .fontWeight(FontWeight.Bold)
    .margin({bottom: 30})
  
  Image(this.isConnected ? 'resources/connected.png' : 'resources/disconnected.png')
    .width(120)
    .height(120)
    .margin({bottom: 20})
  
  if (this.isAlerting) {
    Text('低电量报警!')
      .fontSize(18)
      .fontColor('#FF5252')
      .margin({bottom: 10})

Text(电量: ${this.batteryLevel}%)

    .fontSize(18)
    .fontColor(this.batteryLevel <= 20 ? '#FF5252' : '#333333')
    .margin({bottom: 30})
  
  Text(this.isConnected ? '已连接至手机' : '等待连接...')
    .fontSize(16)
    .margin({bottom: 20})
  
  if (!this.isConnected) {
    Button('配对手机')
      .width(200)
      .height(50)
      .onClick(() => {
        bluetooth.enableBluetooth();
        bluetooth.startBluetoothDiscovery();
      })

}

.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.backgroundColor('#212121')

}

四、与游戏同步技术的结合点
实时状态同步:借鉴游戏中玩家状态同步机制,实现防丢器状态的实时同步

设备发现机制:使用类似游戏大厅的设备发现方式快速配对防丢器

距离感知算法:参考游戏中玩家距离计算优化信号强度到距离的转换

多设备协同:类似游戏多设备协作,实现主从设备间的报警联动

低功耗优化:应用游戏中的移动设备功耗优化策略

五、关键特性实现
精准距离估算:

  // 基于RSSI的卡尔曼滤波距离估算

private kalmanFilterRssi(rssi: number): number {
const Q = 0.1; // 过程噪声协方差
const R = 2.0; // 观测噪声协方差

 if (!this.kalman) {
   this.kalman = { estimate: rssi, error: 1 };

else {

   // 预测
   const predError = this.kalman.error + Q;
   // 更新
   const gain = predError / (predError + R);
   this.kalman.estimate = this.kalman.estimate + gain * (rssi - this.kalman.estimate);
   this.kalman.error = (1 - gain) * predError;

return this.kalman.estimate;

位置追踪优化:

  // 融合蓝牙和GPS数据

private fusePosition(bluetoothPos: Position, gpsPos: Position): Position {
const alpha = 0.7; // 蓝牙数据权重
return {
latitude: alpha bluetoothPos.latitude + (1 - alpha) gpsPos.latitude,
longitude: alpha bluetoothPos.longitude + (1 - alpha) gpsPos.longitude
};

低功耗模式:

  // 根据电量调整扫描频率

private adjustScanInterval(batteryLevel: number): number {
if (batteryLevel > 50) return 5000; // 5秒
if (batteryLevel > 20) return 10000; // 10秒
return 30000; // 30秒

报警策略:

  // 分级报警策略

private triggerLeveledAlert(distanceRatio: number): void {
if (distanceRatio > 2) {
// 强烈报警(声音+震动)
this.fullAlert();
else if (distanceRatio > 1.5) {

   // 中等报警(震动)
   this.vibrationAlert();

else if (distanceRatio > 1) {

   // 轻微报警(通知)
   this.notificationAlert();

}

六、性能优化策略
自适应扫描间隔:

  // 根据连接状态调整扫描频率

if (device.isConnected) {
this.scanInterval = 10000; // 已连接设备降低扫描频率
else {

 this.scanInterval = 5000;  // 未连接设备提高扫描频率

数据压缩传输:

  // 压缩设备状态数据

compressDeviceData(device: TrackerDevice): Uint8Array {
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
// 将关键数据打包到16字节
view.setUint32(0, device.lastConnected / 1000);
view.setInt16(4, device.lastRssi);
view.setUint8(6, device.batteryLevel);
// …其他字段
return new Uint8Array(buffer);

差异化设备处理:

  // 根据设备类型调整功能

if (device.type === ‘tracker’) {
this.enableLowPowerMode();
else if (device.type === ‘phone’) {

 this.enableFullFeatures();

后台运行优化:

  // 注册后台任务

backgroundTaskManager.startBackgroundRunning({
wantAgent: wantAgent,
backgroundMode: backgroundTaskManager.BackgroundMode.LOCATION
}).then(() => {
this.startBackgroundTracking();
});

七、项目扩展方向
群体防丢网络:多用户共享设备位置信息

智能家居集成:与智能门锁联动防止钥匙丢失

历史轨迹回放:记录设备移动轨迹

AI预测提醒:基于习惯预测可能遗忘场景

AR寻物引导:通过AR箭头指引丢失物品方向

八、总结

本蓝牙防丢器应用实现了以下核心功能:
蓝牙设备间的距离实时监测

超出安全距离的多级报警系统

设备状态的分布式同步

低功耗运行模式

最后已知位置记录

通过借鉴游戏中的多设备同步技术,我们构建了一个可靠、高效的防丢系统。该项目展示了HarmonyOS分布式能力在物联网安全领域的创新应用,为开发者提供了实现蓝牙近距离感知应用的参考方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐