HarmonyOS鸿蒙Next中蓝牙设备可配对成功但是连接却是一直失败,代码写在下面了,就是在连接到时候出现问题,连接不上,希望有大佬解决

HarmonyOS鸿蒙Next中蓝牙设备可配对成功但是连接却是一直失败,代码写在下面了,就是在连接到时候出现问题,连接不上,希望有大佬解决

import { access } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

//适配器管理器
export class AdapterManager {
  // 定义蓝牙开关状态变化函数回调
  onReceiveEvent = (data: access.BluetoothState) => {
    let btStateMessage = '';
    switch (data) {
      case access.BluetoothState.STATE_OFF:
        // 表示蓝牙是关闭的
        btStateMessage += 'STATE_OFF';
        break;
      case access.BluetoothState.STATE_TURNING_ON:
        btStateMessage += 'STATE_TURNING_ON';
        break;
      case access.BluetoothState.STATE_ON:
        // 表示蓝牙是开启的,此时应用才可以使用蓝牙其他功能
        btStateMessage += 'STATE_ON';
        break;
      case access.BluetoothState.STATE_TURNING_OFF:
        btStateMessage += 'STATE_TURNING_OFF';
        break;
      case access.BluetoothState.STATE_BLE_TURNING_ON:
        btStateMessage += 'STATE_BLE_TURNING_ON';
        break;
      case access.BluetoothState.STATE_BLE_ON:
        btStateMessage += 'STATE_BLE_ON';
        break;
      case access.BluetoothState.STATE_BLE_TURNING_OFF:
        btStateMessage += 'STATE_BLE_TURNING_OFF';
        break;
      default:
        btStateMessage += 'unknown state';
        break;
    }
    console.info('bluetooth state: ' + btStateMessage);
  };

  // 开启蓝牙
  public openBluetooth() {
    try {
      access.on('stateChange', this.onReceiveEvent);
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
    try {
      // 主动获取蓝牙当前的开关状态
      let state = access.getState();
      if (state == access.BluetoothState.STATE_OFF) {
        // 若蓝牙是关闭的,则主动开启蓝牙
        access.enableBluetooth();
      }
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  // 关闭蓝牙
  public closeBluetooth() {
    try {
      // 主动获取蓝牙当前的开关状态
      let state = access.getState();
      if (state == access.BluetoothState.STATE_ON) {
        // 若蓝牙是开启的,则主动关闭蓝牙
        access.disableBluetooth();
      }
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
}

let adapterManager = new AdapterManager();

export default adapterManager as AdapterManager;
import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

//发现设备管理器
export class DiscoveryDeviceManager {
  // 定义扫描结果上报回调函数
  onReceiveEvent = (data: Array<string>) => {
    console.info('bluetooth device: ' + JSON.stringify(data));
  };

  public startDiscovery() {
    try {
      connection.on('bluetoothDeviceFind', this.onReceiveEvent);
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
    try {
      // 判断本机设备是否正在进行扫描
      let scan = connection.isBluetoothDiscovering();
      if (!scan) {
        // 若当前不处于扫描过程,则开始扫描设备
        connection.startBluetoothDiscovery();
      }
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  public stopDiscovery() {
    try {
      // 判断本机设备是否正在进行扫描
      let scan = connection.isBluetoothDiscovering();
      if (scan) {
        // 若当前处于扫描过程,则停止扫描设备
        connection.stopBluetoothDiscovery();
      }
      // 若不再需要使用扫描,可以取消订阅扫描上报结果
      connection.off('bluetoothDeviceFind', this.onReceiveEvent);
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  public setScanMode() {
    try {
      // 获取当前本机的扫描模式
      let scanMode: connection.ScanMode = connection.getBluetoothScanMode();
      console.info('scanMode: ' + scanMode);
      if (scanMode != connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE) {
        // 将本机设备的扫描模式设为可被发现和可被连接
        connection.setBluetoothScanMode(connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, 0);
      }
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  public getPairedDevices() {
    try {
      // 获取已配对设备信息
      let devices = connection.getPairedDevices();
      console.info('pairedDevices: ' + JSON.stringify(devices));
      // 若已知道设备地址,可主动查询该设备是否是已配对的
      if (devices.length > 0) {
        let pairState = connection.getPairState(devices[0]);
        console.info('device: ' + devices[0] + ' pairState is ' + pairState);
      }
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
}

let discoveryDeviceManager = new DiscoveryDeviceManager();

export default discoveryDeviceManager as DiscoveryDeviceManager;
import { connection, a2dp, hfp, hid, baseProfile, constant } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
//配对设备管理器
export class PairDeviceManager {
  device: string = '';
  pairState: connection.BondState = connection.BondState.BOND_STATE_INVALID;
  a2dpSrc = a2dp.createA2dpSrcProfile();
  hfpAg = hfp.createHfpAgProfile();
  hidHost = hid.createHidHostProfile();
  // 定义配对状态变化回调函数
  onBondStateEvent = (data: connection.BondStateParam) => {
    console.info('pair result: ' + JSON.stringify(data));
    if (data && data.deviceId == this.device) {
      this.pairState = data.state; // 保存目标设备的配对状态
    }
  };

  // 发起配对,设备地址可以通过查找设备流程获取
  public startPair(device: string) {
    this.device = device;
    try {
      // 发起订阅配对状态变化事件
      connection.on('bondStateChange', this.onBondStateEvent);
    } catch (err) {
      console.error('bondStateChange errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }

    try {
      // 发起配对
      connection.pairDevice(device).then(() => {
        console.info('pairDevice');
      }, (error: BusinessError) => {
        console.error('pairDevice: errCode:' + error.code + ',errMessage' + error.message);
      });
    } catch (err) {
      console.error('startPair: errCode:' + err.code + ',errMessage' + err.message);
    }
  }

  // 定义A2DP连接状态变化回调函数
  onA2dpConnectStateChange = (data: baseProfile.StateChangeParam) => {
    console.info(`A2DP State: ${JSON.stringify(data)}`);
  };
  // 定义HFP连接状态变化回调函数
  onHfpConnectStateChange = (data: baseProfile.StateChangeParam) => {
    console.info(`HFP State: ${JSON.stringify(data)}`);
  };
  // 定义HID连接状态变化回调函数
  onHidConnectStateChange = (data: baseProfile.StateChangeParam) => {
    console.info(`HID State: ${JSON.stringify(data)}`);
  };

  // 发起连接
  public async connect(device: string) {
    try {
      let uuids = await connection.getRemoteProfileUuids(device);
      console.info('device: ' + device + ' remoteUuids: ' + JSON.stringify(uuids));
      let allowedProfiles = 0;
      // 若存在应用需要的profile,则监听对应的profile连接状态
      if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_A2DP_SINK.toLowerCase())) {
        console.info('device supports a2dp');
        allowedProfiles++;
        this.a2dpSrc.on('connectionStateChange', this.onA2dpConnectStateChange);
      }
      if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HFP_HF.toLowerCase())) {
        console.info('device supports hfp');
        allowedProfiles++;
        this.hfpAg.on('connectionStateChange', this.onHfpConnectStateChange);
      }
      if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HID.toLowerCase()) ||
      uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HOGP.toLowerCase())) {
        console.info('device supports hid');
        allowedProfiles++;
        this.hidHost.on('connectionStateChange', this.onHidConnectStateChange);
      }
      if (allowedProfiles > 0) { // 若存在可用的profile,则发起连接
        connection.connectAllowedProfiles(device).then(() => {
          console.info('connectAllowedProfiles');
        }, (error: BusinessError) => {
          console.error('errCode:' + error.code + ',errMessage' + error.message);
        });
      }
    } catch (err) {
      console.error('errCode:' + err.code + ',errMessage' + err.message);
    }
  }
}

let pairDeviceManager = new PairDeviceManager();

export default pairDeviceManager as PairDeviceManager;
import { socket } from '@kit.ConnectivityKit'
import { BusinessError } from '@kit.BasicServicesKit';

class SppClientManager {
  // 定义客户端的socket id
  clientNumber: number = -1;

  // 发起连接
  public startConnect(peerDevice: string): void {
    // 配置连接参数
    let option: socket.SppOptions = {
      uuid: '00009999-0000-1000-8000-00805F9B34FB', // 需要连接的服务端UUID服务,确保服务端支持
      secure: false,
      type: socket.SppType.SPP_RFCOMM
    };
    console.info('startConnect ' + peerDevice);
    socket.sppConnect(peerDevice, option, (err, num: number) => {
      if (err) {
        console.error('startConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' +
        (err as BusinessError).message);
      } else {
        console.info('startConnect clientNumber: ' + num);
        this.clientNumber = num;
      }
    });
    console.info('startConnect after ' + peerDevice);
  }

  // 发送数据
  public sendData(data: ArrayBuffer) {
    console.info('sendData ' + this.clientNumber + ', data length: ' + data.byteLength);
    try {
      socket.sppWrite(this.clientNumber, data); // 使用传入的 data
    } catch (err) {
      console.error('发送失败: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  // 定义接收数据的回调函数
  read = (dataBuffer: ArrayBuffer) => {
    let data = new Uint8Array(dataBuffer);
    console.info('client data: ' + JSON.stringify(data));
  };

  // 接收数据
  public readData() {
    try {
      // 发起订阅
      socket.on('sppRead', this.clientNumber, this.read);
    } catch (err) {
      console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }

  // 断开连接
  public stopConnect() {
    console.info('closeSppClient ' + this.clientNumber);
    try {
      // 取消接收数据订阅
      socket.off('sppRead', this.clientNumber, this.read);
    } catch (err) {
      console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
    try {
      // 从client端断开连接
      socket.sppCloseClientSocket(this.clientNumber);
    } catch (err) {
      console.error('stopConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }
}

let sppClientManager = new SppClientManager();

export default sppClientManager as SppClientManager;
import { socket } from '@kit.ConnectivityKit'
import { BusinessError } from '@kit.BasicServicesKit';

class SppServerManager {
  serverNumber: number = -1;
  clientNumber: number = -1;

  // 创建服务端监听socket
  public startListen(): void {
    console.info('startListen');

    // 配置监听参数
    let option: socket.SppOptions = {
      uuid: '00009999-0000-1000-8000-00805F9B34FB',
      secure: false,
      type: socket.SppType.SPP_RFCOMM
    };

    // 创建服务端监听socket,将在蓝牙子系统中注册该UUID服务
    socket.sppListen("demonstration", option, (err, num: number) => {
      if (err) {
        console.error('sppListen errCode: ' + (err as BusinessError).code + ', errMessage: ' +
        (err as BusinessError).message);
      } else {
        console.info('sppListen serverNumber: ' + num);
        this.serverNumber = num;
      }
    });
  }

  // 监听连接请求,等待连接
  public accept() {
    console.info('accept ' + this.serverNumber);
    if (this.serverNumber == -1) {
      console.error('invalid serverNumber');
      return;
    }
    socket.sppAccept(this.serverNumber, (err, num: number) => {
      if (err) {
        console.error('accept errCode: ' + (err as BusinessError).code + ', errMessage: ' +
        (err as BusinessError).message);
      } else {
        console.info('accept clientNumber: ' + num);
        this.clientNumber = num;
      }
    });
  }

  // 发送数据
  public sendData() {
    console.info('sendData serverNumber: ' + this.serverNumber + ' clientNumber: ' + this.clientNumber);
    if (this.clientNumber == -1) {
      console.error('invalid clientNumber');
      return;
    }
    let arrayBuffer = new ArrayBuffer(2);
    let data = new Uint8Array(arrayBuffer);
    data[0] = 9;
    data[1] = 8;
    try {
      socket.sppWrite(this.clientNumber, arrayBuffer);
    } catch (err) {
      console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }

  // 定义接收数据的回调函数
  read = (dataBuffer: ArrayBuffer) => {
    let data = new Uint8Array(dataBuffer);
    console.info('client data: ' + JSON.stringify(data));
  };

  // 接收数据
  public readData() {
    try {
      // 发起订阅
      if (this.clientNumber == -1) {
        console.error('invalid clientNumber');
        return;
      }
      socket.on('sppRead', this.clientNumber, this.read);
    } catch (err) {
      console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }

  // 停止连接
  public stopConnect() {
    console.info('stopConnect');
    try {
      // 取消订阅
      if (this.clientNumber == -1) {
        console.error('invalid clientNumber');
        return;
      }
      socket.off('sppRead', this.clientNumber, this.read);
    } catch (err) {
      console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
    try {
      // 从server断开连接
      socket.sppCloseClientSocket(this.clientNumber);
    } catch (err) {
      console.error('stopConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }

  // 删除能力
  public closeSppServer() {
    console.info('closeSppServer');
    try {
      // 若应用不再需要此能力,则主动删除
      if (this.serverNumber == -1) {
        console.error('invalid serverNumber');
        return;
      }
      socket.sppCloseServerSocket(this.serverNumber);
    } catch (err) {
      console.error('sppCloseServerSocket errCode: ' + (err as BusinessError).code + ', errMessage: ' +
      (err as BusinessError).message);
    }
  }
}

let sppServerManager = new SppServerManager();

export default sppServerManager as SppServerManager;
import adapterManager from '../manager/AdapterManager';
import discoveryDeviceManager from '../manager/DiscoveryDeviceManager';
import pairDeviceManager from '../manager

更多关于HarmonyOS鸿蒙Next中蓝牙设备可配对成功但是连接却是一直失败,代码写在下面了,就是在连接到时候出现问题,连接不上,希望有大佬解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

【背景知识】

蓝牙socket:提供了操作和管理蓝牙socket的方法。

【参考方案】 可参考蓝牙通信示例,通过@ohos.bluetooth.socket实现蓝牙通信,完成设备之间的信息发送效果。

  1. sppConnect():调用socket.sppConnect方法,尝试与指定MAC地址的蓝牙设备建立SPP连接。
sppConnect() {
  ······
  let sppOption: socket.SppOptions = { uuid: Constants.UUID, secure: false, type: 0 };
  try {
    socket.sppConnect(this.mac, sppOption, clientSocket);
  } 
  ······
}
  1. sppListen():调用socket.sppListen方法,在蓝牙设备上启动SPP服务,等待其他设备连接。
sppListen() {
  let sppOption: socket.SppOptions = { uuid: Constants.UUID, secure: false, type: 0 };
  try {
    socket.sppListen('BT_SOCKET', sppOption, (code: BusinessError, number: number) => {
      this.sppAccept()
    } 
  }
}
  1. sppAccept():依赖于sppListen启动服务端监听后,接受客户端的SPP连接请求。
sppAccept() {
  try {
    socket.sppAccept(this.serverNumber, (code: BusinessError, number: number) => {
      ······
    });
  } 
}
  1. msgSend():调用socket.sppWrite方法,向已连接的客户端发送消息。
msgSend() {
  ······
  try {
    socket.sppWrite(this.clientNumber, Utils.string2ArrayBuffer(this.msgValue));
    this.msgList.push(new MsgShow(this.msgValue, true))
    this.msgValue = '';
  } 
  ······
}
  1. onSppRead():注册SPP数据读取监听器,接收来自客户端的数据。
onSppRead() {
  ······
  try {
    socket.on('sppRead', this.clientNumber, (dataBuffer: ArrayBuffer) => {
      let data = Utils.ArrayBuffer2String(dataBuffer);
      this.msgList.push(new MsgShow(data, false))
    });
    this.msgReadSwitch = true;
  } 
}

更多关于HarmonyOS鸿蒙Next中蓝牙设备可配对成功但是连接却是一直失败,代码写在下面了,就是在连接到时候出现问题,连接不上,希望有大佬解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


1.尝试修改这里的参数:

// 配置监听参数
let option: socket.SppOptions = {
  uuid: '00009999-0000-1000-8000-00805F9B34FB',
  secure: true,
  type: socket.SppType.SPP_RFCOMM
};

2.楼主的代码太多了 希望楼主提供一个git仓库,在仓库里面搭建一个最小页面的项目共享出来调试

git clone https://gitee.com/liuyongzhengnb/test.git

你这个项目跑不起来,

楼主你这个太长了,就不一一看了,你先看下权限配置,在config.json中配ohos.permission.BLUETOOTH权限。

{
  "module": {
    "reqPermissions": [
      { "name": "ohos.permission.BLUETOOTH" }
    ]
  }
}

然后在连接前停止蓝牙扫描,因为如果资源占用会导致连接失败,前提得确保设备处于可发现模式且没有被其他占用

discoveryDeviceManager.stopDiscovery(); // 在连接前停止扫描

对了你再通过connection.getConnectedDevices()获取当前连接设备列表。检查一下已连接设备数量,别超过阈值。

别的没发现问题,关键代码优化一下再试试,前面几点别忘了确认

public async connect(device: string) {
  try {
    // 停止扫描释放资源
    this.discoveryDeviceManager.stopDiscovery();
    
    // 获取设备支持的Profile
    const uuids = await connection.getRemoteProfileUuids(device);
    if (uuids.length === 0) {
      console.error('设备不支持任何可用配置文件');
      return;
    }

    // 监听连接状态变化
    this.setupProfileListeners(uuids);
    
    // 发起连接
    await connection.connectAllowedProfiles(device);
    console.info('连接请求已发起');
  } catch (error) {
    console.error(`连接异常,错误码:${(error as BusinessError).code}, 信息:${error.message}`);
  }
}

在鸿蒙Next中蓝牙连接失败可能原因:

  1. 设备UUID未正确配置,需与蓝牙设备厂商提供的服务UUID完全匹配
  2. 未添加ohos.permission.DISCOVER_BLUETOOTH和ohos.permission.MANAGE_BLUETOOTH权限
  3. 连接时机不当,建议在onCharacteristicWrite回调成功后发起连接
  4. 未正确处理设备状态变化,需监听bluetoothManager.subscribeStateChange事件

检查点:

  • 确认设备支持BLE协议
  • 配对后等待2-3秒再连接
  • 设备是否已被其他主机连接
  • 系统蓝牙服务是否正常启动

从代码来看,蓝牙配对成功但连接失败的问题可能出在以下几个关键点:

  1. 连接逻辑问题:
  • 在PairDeviceManager的connect方法中,虽然检查了设备支持的profile,但connectAllowedProfiles()调用后没有正确处理连接状态回调
  • 缺少对连接超时的处理机制
  1. Profile连接问题:
  • 代码中只订阅了A2DP/HFP/HID的连接状态变化,但实际连接时没有等待这些profile真正连接完成
  • 需要确认设备实际支持的profile与服务端是否匹配
  1. SPP连接问题:
  • SPP连接(sppConnect)与profile连接是独立的,需要确保两者都成功
  • UUID '00009999-0000-1000-8000-00805F9B34FB’需要确认是否与设备端一致

建议修改:

  1. 在PairDeviceManager中增强连接处理:
public async connect(device: string) {
  try {
    let uuids = await connection.getRemoteProfileUuids(device);
    let profilesToConnect = [];
    
    // 检查并准备需要连接的profile
    if(uuids.some(uuid => uuid === constant.ProfileUuids.PROFILE_UUID_A2DP_SINK.toLowerCase())){
      profilesToConnect.push(this.a2dpSrc.connect(device));
    }
    // 其他profile检查...

    // 并行连接所有支持的profile
    await Promise.all(profilesToConnect);
    
    // 然后建立SPP连接
    await new Promise<void>((resolve, reject) => {
      socket.sppConnect(device, {uuid: '00009999...', ...}, (err, num) => {
        if(err) reject(err);
        else {
          this.clientNumber = num;
          resolve();
        }
      });
    });

  } catch(err) {
    console.error('连接失败:', err);
    throw err;
  }
}
  1. 增加连接状态监控:
// 在连接方法中添加状态监听
this.a2dpSrc.on('connectionStateChange', (state) => {
  if(state === baseProfile.ProfileConnectionState.STATE_DISCONNECTED){
    console.error('A2DP连接断开');
  }
});
  1. 检查设备兼容性:
  • 确认设备确实支持声明的profile
  • 检查SPP服务的UUID是否匹配
  • 验证设备是否要求安全连接(secure参数)
  1. 错误处理:
  • 添加连接超时机制
  • 区分不同类型的连接错误(profile连接错误 vs SPP连接错误)

建议先在简单场景测试:

  1. 先单独测试profile连接
  2. 再单独测试SPP连接
  3. 最后测试完整流程

注意查看日志中具体的错误码,这对定位问题很有帮助。

回到顶部