HarmonyOS 鸿蒙Next中蓝牙扫描不显示和手机连接中的蓝牙怎么办啊,只显示未连接的蓝牙

HarmonyOS 鸿蒙Next中蓝牙扫描不显示和手机连接中的蓝牙怎么办啊,只显示未连接的蓝牙

3 回复
import adapterManager from '../manager/AdapterManager';
import discoveryDeviceManager from '../manager/DiscoveryDeviceManager';
import pairDeviceManager from '../manager/PairDeviceManager';
import sppClientManager from '../manager/SppClientManager';
import { access, baseProfile, connection } from '[@kit](/user/kit).ConnectivityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { promptAction } from '[@kit](/user/kit).ArkUI';
import { Permissions } from '[@kit](/user/kit).AbilityKit';
import abilityAccessCtrl from '[@ohos](/user/ohos).abilityAccessCtrl';
import bundleManager from '[@ohos](/user/ohos).bundle.bundleManager';
import common from '[@ohos](/user/ohos).app.ability.common';

// 定义连接状态接口
interface IProfileConnectionState {
  STATE_DISCONNECTED: number;
  STATE_CONNECTING: number;
  STATE_CONNECTED: number;
  STATE_DISCONNECTING: number;
}

// 定义连接状态枚举
export enum ProfileConnectionState {
  STATE_DISCONNECTED = 0, // 断开连接
  STATE_CONNECTING = 1, // 正在连接
  STATE_CONNECTED = 2, // 已连接
  STATE_DISCONNECTING = 3 // 正在断开
}

// 定义常量对象并指定接口类型
export const ProfileConnectionStateConst: IProfileConnectionState = {
  STATE_DISCONNECTED: ProfileConnectionState.STATE_DISCONNECTED,
  STATE_CONNECTING: ProfileConnectionState.STATE_CONNECTING,
  STATE_CONNECTED: ProfileConnectionState.STATE_CONNECTED,
  STATE_DISCONNECTING: ProfileConnectionState.STATE_DISCONNECTING
};

// 设备信息接口
/**
 * 蓝牙设备信息接口,用于描述蓝牙设备的核心属性
 */
interface BluetoothDevice {
  /**
   * 设备的蓝牙物理地址(MAC地址)
   * 格式为"XX:XX:XX:XX:XX:XX",全球唯一,用于设备的唯一标识
   * 例如:"60:66:A3:4A:D3:90"
   */
  address: string;

  /**
   * 设备的名称(友好名称)
   * 由设备广播或通过查询获取,可能为空或为默认名称(如"设备+MAC前缀")
   * 例如:"MO2QMo45kBOJfIZxTD+yBJX2o"或"蓝牙音箱"
   */
  name: string;

  /**
   * 设备的配对状态
   * true表示已与当前设备完成配对,false表示未配对
   */
  paired: boolean;

  /**
   * 设备的连接状态
   * true表示当前与该设备保持连接,false表示未连接
   */
  connected: boolean;

  /**
   * 设备类型(新增)
   * 用于确定显示的图标类型
   */
  type?: 'phone' | 'headset' | 'speaker' | 'car' | 'watch' | 'other';
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct BluetoothIntegrationPage {
  // 蓝牙状态(使用[@State](/user/State)确保UI联动更新)
  [@State](/user/State) isBluetoothOn: boolean = false;
  // 扫描状态(添加[@State](/user/State)触发UI刷新)
  [@State](/user/State) isScanning: boolean = false;
  // 已发现设备列表
  [@State](/user/State) devices: BluetoothDevice[] = [];
  // 已配对设备列表
  [@State](/user/State) pairedDevices: BluetoothDevice[] = [];
  // 当前选中设备
  [@State](/user/State) selectedDevice: string = '';
  // 加载状态
  [@State](/user/State) isLoading: boolean = false;
  // 发送的数据
  [@State](/user/State) sendData: string = '';
  // 设备配对状态
  [@State](/user/State) devicePairingStates: Record<string, boolean> = {}; // key: address, value: 是否正在配对
  // 设备连接中状态(key: 设备address,value: 是否正在连接)
  [@State](/user/State) deviceConnectingStates: Record<string, boolean> = {};
  // 在类中添加配对超时处理
  private pairingTimeout: Map<string, number> = new Map();

  aboutToAppear() {
    // 优先检查权限
    this.ensureBluetoothPermissions().then((hasPermissions) => {
      if (hasPermissions) {
        this.initManagers(); // 初始化管理器回调
        this.initBluetoothState(); // 初始化蓝牙状态
      } else {
        console.warn('蓝牙权限未授予,功能受限');
        promptAction.showToast({ message: '请授予蓝牙权限以使用功能' });
      }
      // 关键修改:无论蓝牙是否开启,只要有权限就加载已配对设备
      if (hasPermissions) {
        this.loadPairedDevices();
      }
    });
  }

  build() {
    // 使用Scroll作为作为最外层容器,实现整个页面滚动
    Scroll() {
      Column() {
        // 标题栏
        Row() {
          Text('蓝牙设备管理器')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#ffffff');
        }
        .justifyContent(FlexAlign.Center)
        .padding(16)
        .backgroundColor('#1677ff')
        .width('100%')

        // 蓝牙开关
        Row() {
          Text('蓝牙状态')
            .fontSize(16);

          Toggle({ type: ToggleType.Switch, isOn: this.isBluetoothOn })
            .onChange((checked) => this.toggleBluetooth(checked));
        }
        .justifyContent(FlexAlign.SpaceBetween)
        .alignItems(VerticalAlign.Center)
        .padding(16)
        .backgroundColor('#ffffff')
        .margin({ top: 8 })
        .width('100%')

        // 扫描控制
        Row() {
          // 扫描中显示进度圈
          if (this.isScanning) {
            LoadingProgress()
              .size({ width: 20, height: 20 })

              .margin({ right: 8 });
          }
          Button(this.isScanning ? '停止扫描' : '开始扫描')
            .onClick(() => this.isScanning ? this.stopScan() : this.startScan())
            .backgroundColor(this.isScanning ? '#ff4d4f' : '#1677ff')
            .padding({ left: 20, right: 20 })
            .enabled(this.isBluetoothOn);
        }
        .justifyContent(FlexAlign.Center)
        .alignItems(VerticalAlign.Center) // 新增:确保进度圈与按钮垂直居中
        .padding(16)
        .width('100%')

        // 已配对设备标题

        Text('已配对设备')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .padding(16)
          .width('100%')
          .backgroundColor('#f5f5f5');

        // 已配对设备列表
        List() {
          ForEach(this.pairedDevices, (device: BluetoothDevice) => {
            ListItem() {
              this.buildDeviceItem(device)
            }
          }, (device: BluetoothDevice) => device.address)
        }
        .width('100%')
        .divider({ strokeWidth: 1, color: Color.Gray })
        .margin({ bottom: 16 })


        // 设备列表标题
        Text('已发现设备')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .padding(16)
          .width('100%')
          .backgroundColor('#f5f5f5');

        // 设备列表
        List() {
          ForEach(this.devices, (device: BluetoothDevice) => {
            ListItem() {
              this.buildDeviceItem(device)
            }
          }, (device: BluetoothDevice) => device.address);
        }
        .width('100%')
        .divider({ strokeWidth: 1, color: Color.Gray })
        .margin({ bottom: 20 }) // 底部留白,避免最后一项被遮挡
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start) // 确保内容左对齐
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#fafafa')
    .align(Alignment.Top)
    .scrollBar(BarState.Off)
  }

  [@Builder](/user/Builder)
  buildDeviceItem(device: BluetoothDevice) {
    Column() {
      Row() {
        // 设备图标
        Image(this.getDeviceIcon(device.type))
          .width(40)
          .height(40)
          .margin({ right: 12 })

        // 设备信息区域
        Column() {
          Text(`${device.name}`)
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .fontColor(Color.Red);
          Text(`MAC地址: ${device.address}`)
            .fontSize(12)
            .fontColor('#666666')
            .margin({ top: 4 });
        }
        .layoutWeight(1) // 占据剩余空间

        // 操作按钮区域
        Row() {
          // 配对中状态
          if (this.devicePairingStates[device.address]) {
            LoadingProgress()
              .size({ width: 20, height: 20 })
              .color('#1677ff')
              .margin({ right: 8 });
          }
          // 连接中状态(新增)
          else if (this.deviceConnectingStates[device.address]) {
            LoadingProgress()
              .size({ width: 20, height: 20 })
              .color('#1677ff')
              .margin({ right: 8 });
          }
          // 已连接状态
          else if (device.connected) {
            Button('断开')
              .onClick(() => this.disconnectDevice(device.address))
              .backgroundColor(Color.Red)
              .padding({ left: 12, right: 12 });
          }
          // 已配对但未连接
          else if (device.paired) {
            Button('连接')
              .onClick(() => this.connectDevice(device.address))
              .backgroundColor(Color.Green)
              .padding({ left: 12, right: 12 });
          }
          // 未配对
          else {
            Button('配对')
              .onClick(() => this.pairDevice(device.address))
              .backgroundColor('#0050b3')
              .padding({ left: 12, right: 12 })
              .enabled(!this.devicePairingStates[device.address]);
          }
        }
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .width('100%')
      .margin({ bottom: 8 })

      // 数据发送区域(仅对已连接设备显示)
      if (device.connected && this.selectedDevice === device.address) {
        Row() {
          TextInput({ placeholder: '输入要发送的数据', text: this.sendData })
            .onChange((value) => this.sendData = value)
            .height(40)
            .flexGrow(1)
            .border({ width: 1, color: '#dddddd' })
            .padding({ left: 12 });

          Button('发送')
            .onClick(() => this.sendDataToDevice())
            .backgroundColor('#1677ff')
            .margin({ left: 8 })
            .padding({ left: 16, right: 16 });
        }
        .alignItems(VerticalAlign.Center)
        .margin({ top: 8 })
        .width('100%')
      }
    }
    .padding(16)
  }

  // 加载已配对设备
  private loadPairedDevices() {
    try {
      const pairedDevices = connection.getPairedDevices();
      this.pairedDevices = pairedDevices.map(address => {
        let name = '';
        try {
          name = connection.getRemoteDeviceName(address) || '';
        } catch (err) {
          console.error(`获取配对设备${address}名称失败: ${(err as BusinessError).code}`);
        }

        const device: BluetoothDevice = {
          address: address,
          name: name,
          paired: true,
          connected: false,
          type: this.detectDeviceType(name)
        };
        return device;
      });
    } catch (err) {
      console.error('加载已配对设备失败: ' + (err as BusinessError).code);
    }
  }

  // 检测设备类型
  private detectDeviceType(name: string): 'phone' | 'headset' | 'speaker' | 'car' | 'watch' | 'other' {
    const lowerName = name.toLowerCase();

    if (lowerName.includes('phone') || lowerName.includes('手机')) {
      return 'phone';
    } else if (lowerName.includes('headset') || lowerName.includes('耳机')) {
      return 'headset';
    } else if (lowerName.includes('speaker') || lowerName.includes('音箱')) {
      return 'speaker';
    } else if (lowerName.includes('car') || lowerName.includes('车载')) {
      return 'car';
    } else if (lowerName.includes('watch') || lowerName.includes('手表')) {
      return 'watch';
    } else {
      return 'other';
    }
  }

  // 初始化管理器回调(核心:复用管理器的事件监听)
  private initManagers() {
    // 1. 蓝牙状态变化:复用AdapterManager的回调
    const originalAdapterCallback = adapterManager.onReceiveEvent;
    adapterManager.onReceiveEvent = (state: access.BluetoothState) => {
      originalAdapterCallback(state); // 保留管理器原有日志
      // 同步页面蓝牙状态
      this.isBluetoothOn = state === access.BluetoothState.STATE_ON;
      if (!this.isBluetoothOn) {
        console.warn('【页面】蓝牙已关闭,停止扫描并清空设备');
        this.stopScan();
        this.devices = [];

      }
    };

    // 2. 设备发现:复用DiscoveryDeviceManager的回调
    const originalDiscoveryCallback = discoveryDeviceManager.onReceiveEvent;
    discoveryDeviceManager.onReceiveEvent = async (addresses: string[]) => {
      originalDiscoveryCallback(addresses); // 保留管理器原有日志
      console.warn(`【页面】发现新设备,共${addresses.length}个`);

      for (const address of addresses) {
        if (!this.devices.some(device => device.address === address) &&
          !this.pairedDevices.some(device => device.address === address)) {
          let deviceName = ''; // 无名称时默认空字符串(不再用MAC替代)
          try {
            // 仅保留实际获取到的名称,无名称则为空
            deviceName = await connection.getRemoteDeviceName(address) || '';
          } catch (err) {
            console.error(`【页面】获取设备${address}名称失败: ${(err as BusinessError).code}`);
          }
          // :仅添加设备名称不为空的设备
          if (deviceName.trim() !== '') {
            // 添加设备到列表
            const newDevice: BluetoothDevice = {
              address,
              name: deviceName,
              paired: false,
              connected: false,
              type: this.detectDeviceType(deviceName)
            };
            this.devices = [...this.devices, newDevice];
            // 打印设备详细信息
            console.warn(`【页面】发现设备 - 名称: ${deviceName}, MAC地址: ${address}`);
            this.checkDevicePairState(address); // 检查配对状态
          } else {
            console.warn(`【页面】设备${address}名称为空,不显示该设备`);
          }
        }
      }
    };

    // 3. 配对状态变化:复用PairDeviceManager的回调
    const originalPairCallback = pairDeviceManager.onBondStateEvent;
    pairDeviceManager.onBondStateEvent = (data: connection.BondStateParam) => {
      originalPairCallback(data);

      // 清除加载状态
      const deviceAddress = data.deviceId;
      this.devicePairingStates[deviceAddress] = false;

      // 清除配对超时
      const timeoutId = this.pairingTimeout.get(data.deviceId);
      if (timeoutId) {
        clearTimeout(timeoutId);
        this.pairingTimeout.delete(data.deviceId);
      }

      const index = this.devices.findIndex(device => device.address === data.deviceId);
      if (index !== -1) {
        const device = this.devices[index];
        const isPaired = data.state === connection.BondState.BOND_STATE_BONDED;

        // 更新设备配对状态
        const newDevices = [...this.devices];
        newDevices[index].paired = isPaired;
        this.devices = newDevices;

        // 如果配对成功,添加到已配对列表
        if (isPaired) {
          const newPairedDevice: BluetoothDevice = {
            address: device.address,
            name: device.name,
            paired: true,
            connected: device.connected,
            type: this.detectDeviceType(device.name)
          };


          this.pairedDevices = [...this.pairedDevices, newPairedDevice];
          // 从发现列表中移除
          this.devices = this.devices.filter(d => d.address !== device.address);
        }

        // 显示配对结果
        if (isPaired) {
          promptAction.showToast({ message: `与 ${device.name} 配对成功` });
        } else {
          console.error(`【页面】配对失败,设备: ${deviceAddress}, 状态码: ${data.state}`);
          promptAction.showToast({ message: `与 ${device.name} 配对失败,请重试` });
        }
      }
    };

    // 4. SPP接收数据回调(补充管理器的read方法)
    const originalSppRead = sppClientManager.read;
    sppClientManager.read = (dataBuffer: ArrayBuffer) => {
      originalSppRead(dataBuffer); // 保留管理器原有日志
      // 解析接收的数据并提示
      // 修复类型错误:明确类型转换
      const data = new Uint8Array(dataBuffer);
      // 将 Uint8Array 转换为 number[]
      const charCodes: number[] = Array.from(data);
      const text = String.fromCharCode(...charCodes);
      promptAction.showToast({ message: `收到数据: ${text}` });
      console.warn(`【页面】收到数据: ${text}`);
    };

    // 5. 监听连接状态变化
    pairDeviceManager.onProfileConnectStateChange = (deviceAddress: string, state: baseProfile.StateChangeParam) => {

      console.warn(`【页面】连接状态变化: ${deviceAddress} -> ${state.state}`);


      // 根据状态更新连接中状态
      if (state.state === ProfileConnectionStateConst.STATE_CONNECTED) {
        // 连接成功:取消连接中状态
        this.deviceConnectingStates[deviceAddress] = false;
        promptAction.showToast({ message

更多关于HarmonyOS 鸿蒙Next中蓝牙扫描不显示和手机连接中的蓝牙怎么办啊,只显示未连接的蓝牙的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,蓝牙扫描仅显示未连接设备而无法识别已配对手机,通常由以下原因导致:系统蓝牙缓存未更新或设备可见性设置问题。请进入设置-蓝牙,关闭蓝牙功能后重新开启,强制刷新设备列表。同时确认目标手机蓝牙处于可被发现模式,且未与其他设备保持活跃连接。若问题持续,尝试清除鸿蒙系统蓝牙共享数据:设置-应用管理-系统应用-蓝牙-存储-删除数据。此操作不会影响已配对信息,但会重置扫描记录。设备需在有效通信范围内(建议10米内无障碍)。

在HarmonyOS Next中,蓝牙扫描仅显示未连接设备是正常行为。系统设计上,已连接的蓝牙设备通常不会重复出现在扫描结果中,以避免干扰用户操作。

建议通过以下步骤排查:

  1. 进入「设置」-「蓝牙」查看已配对设备列表,已连接的设备会在此显示状态
  2. 确认目标设备未被其他终端占用连接(蓝牙设备通常只能保持一个活跃连接)
  3. 尝试关闭/重启蓝牙功能,或重启设备刷新蓝牙服务
  4. 如需要重新连接,建议在已配对列表中删除设备后重新扫描配对

若问题持续存在,可检查系统版本更新或提交错误日志反馈。该设计符合主流蓝牙协议规范,能确保扫描界面的简洁性。

回到顶部