You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React组件与BleManager.js蓝牙扫描通信实现(类iOS代理/观察者模式)

实现类似iOS代理/观察者模式的蓝牙扫描回调逻辑

作为iOS开发者,你习惯用代理或者通知中心来处理这类跨组件的回调逻辑,其实在JavaScript + React的场景下,我们有几种非常贴合的实现方式,刚好能解决你把蓝牙扫描判断逻辑移到React组件的需求。下面我结合你的BleManager.js代码给出具体方案:

方案一:自定义观察者模式(类似iOS NotificationCenter)

这种方式最接近iOS的通知机制,我们可以在BleManager里维护一个观察者列表,每当扫描到设备时就通知所有注册的观察者,由React组件来决定是否停止扫描。

改造BleManager.js

class BleManager {
  constructor() {
    this.observers = []; // 存储观察者列表
    this.currentScanHandler = null; // 保存扫描handler,用于停止扫描
  }

  // 添加观察者
  addObserver(observer) {
    this.observers.push(observer);
  }

  // 移除观察者(防止内存泄漏)
  removeObserver(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  // 通知所有观察者
  notifyObservers(device) {
    this.observers.forEach(observer => observer.onDeviceFound(device));
  }

  startLeScan = () => {
    return new Promise((resolve, reject) => {
      navigator.mozBluetooth.defaultAdapter.startLeScan([])
        .then(handlerLE => {
          this.currentScanHandler = handlerLE; // 保存handler
          handlerLE.ondevicefound = (eventLE) => {
            const device = eventLE.device;
            // 通知所有观察者当前扫描到的设备
            this.notifyObservers(device);
          };
        })
        .catch(e => {
          console.log(e);
          reject({ error: e });
        });
    });
  }

  // 新增停止扫描的方法
  stopLeScan() {
    if (this.currentScanHandler) {
      navigator.mozBluetooth.defaultAdapter.stopLeScan(this.currentScanHandler);
      this.currentScanHandler = null;
    }
  }
}

export default new BleManager(); // 导出单例,方便全局使用

在React组件中使用观察者

import React, { Component } from 'react';
import BleManager from './BleManager';

class BluetoothScanner extends Component {
  componentDidMount() {
    // 注册观察者
    BleManager.addObserver(this);
    // 开始扫描
    BleManager.startLeScan().catch(err => console.error(err));
  }

  componentWillUnmount() {
    // 移除观察者,避免内存泄漏
    BleManager.removeObserver(this);
    // 组件卸载时停止扫描
    BleManager.stopLeScan();
  }

  // 观察者回调方法,对应BleManager里的notifyObservers调用
  onDeviceFound = (device) => {
    console.log('扫描到设备:', device.address, device.name);
    // 这里由组件判断是否为目标设备
    if (device.address === "ed:ec:90:87:5d:86") {
      console.log('找到目标设备,停止扫描');
      BleManager.stopLeScan();
      // 这里可以做后续逻辑,比如连接设备
    }
  }

  render() {
    return (
      <div>
        <h2>蓝牙扫描中...</h2>
      </div>
    );
  }
}

export default BluetoothScanner;

方案二:回调函数模式(类似iOS Block回调)

如果你的场景比较简单,不需要多个观察者,直接给startLeScan传一个回调函数更简洁,类似iOS里的completion block。

改造BleManager.js的startLeScan方法

startLeScan = (onDeviceFoundCallback) => {
  return new Promise((resolve, reject) => {
    navigator.mozBluetooth.defaultAdapter.startLeScan([])
      .then(handlerLE => {
        handlerLE.ondevicefound = (eventLE) => {
          const device = eventLE.device;
          // 调用传入的回调函数,把设备和扫描handler传给组件
          onDeviceFoundCallback(device, handlerLE);
        };
      })
      .catch(e => {
        console.log(e);
        reject({ error: e });
      });
  });
}

在React组件中使用回调

import React, { Component } from 'react';
import BleManager from './BleManager';

class BluetoothScanner extends Component {
  componentDidMount() {
    BleManager.startLeScan((device, handlerLE) => {
      console.log('扫描到设备:', device.address, device.name);
      if (device.address === "ed:ec:90:87:5d:86") {
        console.log('找到目标设备,停止扫描');
        navigator.mozBluetooth.defaultAdapter.stopLeScan(handlerLE);
        // 后续逻辑,比如发起设备连接
      }
    }).catch(err => console.error(err));
  }

  componentWillUnmount() {
    // 若需要在组件卸载时强制停止扫描,可参考方案一在BleManager中实现全局stop方法
  }

  render() {
    return <div>蓝牙扫描中...</div>;
  }
}

export default BluetoothScanner;

方案对比

  • 观察者模式:适合多个组件需要监听蓝牙扫描结果的场景,扩展性强,和iOS的NotificationCenter逻辑完全对齐。
  • 回调函数:适合单一组件监听的简单场景,代码更精简,类似iOS的block回调逻辑。

两种方案都能实现你想要的"由React组件判断目标设备并停止扫描"的需求,你可以根据自己的项目复杂度选择。

内容的提问来源于stack exchange,提问作者sree_iphonedev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 16:27:28