【HarmonyOS】鸿蒙应用蓝牙功能实现 (二)

【HarmonyOS】鸿蒙应用蓝牙功能实现 (二)

前言

蓝牙一般分为传统蓝牙(BR/EDR),低功耗蓝牙(BLE)两种。

鸿蒙将蓝牙的功能模块分的非常细。

基本上我们会用到access进行蓝牙状态的开启和关闭,以及状态查询。

在使用connection进行传统蓝牙模式的扫描和配对。

或者再使用ble低功耗蓝牙模式进行广播,发起广播,传输数据,以及消息订阅。

Demo示例:

dart 复制代码
import { access } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { BlueToothMgr } from '../manager/BlueToothMgr';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { connection } from '@kit.ConnectivityKit';
import { map } from '@kit.ConnectivityKit';
import { pbap } from '@kit.ConnectivityKit';

@Entry
@Component
struct Index {

  private TAG: string = "BlueToothTest";

  // 蓝牙状态
  @State @Watch('onChangeBlueTooth') isStartBlueTooth: boolean = false;
  @State userGrant: boolean = false;

  @State mListDevice: Array<string> = [];

  async aboutToAppear() {
    await this.requestBlueToothPermission();

    let state = access.getState();
    console.log(this.TAG, "getState state: " + state);
    if(state == 2){
      this.isStartBlueTooth = true;
    }else{
      this.isStartBlueTooth = false;
    }
  }

  private onChangeBlueTooth(){
    if(!this.isStartBlueTooth){
      return;
    }
    // 当前设备的蓝牙可发现状态
    try {
      let res: boolean = connection.isBluetoothDiscovering();
      console.info(this.TAG, 'isBluetoothDiscovering: ' + res);
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }

    // 访问信息相关功能
    try {
      let mapMseProfile = map.createMapMseProfile();
      console.info(this.TAG, 'MapMse success:' + JSON.stringify(mapMseProfile));
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }

    // 访问电话簿相关功能
    try {
      let pbapServerProfile = pbap.createPbapServerProfile();
      console.info(this.TAG, 'pbapServer success:' + JSON.stringify(pbapServerProfile));
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }

    try {
      connection.on('bluetoothDeviceFind', (data: Array<string>)=> {
        console.info(this.TAG, 'data length' + JSON.stringify(data));
        // 获取扫描可配对的设备列表
        this.mListDevice = data;
      });
      connection.startBluetoothDiscovery();
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  // 用户申请权限
  async reqPermissionsFromUser(): Promise<number[]> {
    let context = getContext() as common.UIAbilityContext;
    let atManager = abilityAccessCtrl.createAtManager();
    let grantStatus = await atManager.requestPermissionsFromUser(context, ['ohos.permission.ACCESS_BLUETOOTH']);
    return grantStatus.authResults;
  }

  // 用户申请蓝牙权限
  async requestBlueToothPermission() {
    let grantStatus = await this.reqPermissionsFromUser();
    for (let i = 0; i < grantStatus.length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
        this.userGrant = true;
      }
    }
  }

  setBlueToothState =()=>{
    try {
      if(!this.isStartBlueTooth){
        BlueToothMgr.Ins().setBlueToothAccess(true);
      }else{
        BlueToothMgr.Ins().setBlueToothAccess(false);
      }
      let state = access.getState();
      if(state == 2){
        this.isStartBlueTooth = true;
      }else{
        this.isStartBlueTooth = false;
      }
      console.log(this.TAG, "getState state: " + state);
    } catch (err) {
      console.error(this.TAG,'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  build() {
    RelativeContainer() {
      if(this.userGrant){
        Text("蓝牙状态:" + this.isStartBlueTooth ? "开启" : "关闭")
          .id('HelloWorld')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
          .onClick(this.setBlueToothState)

        Text("蓝牙状态:" + this.isStartBlueTooth ? "开启" : "关闭")
          .id('HelloWorld')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
          .onClick(this.setBlueToothState)


      }
    }
    .height('100%')
    .width('100%')
  }

  @Builder ListView(){
    List() {
      ForEach(this.mListDevice, (item: string, index: number) => {
        ListItem() {
          Row() {
            Text(item).fontSize(px2fp(22)).fontColor(Color.Black)
          }
          .width('100%')
          .height(px2vp(100))
          .justifyContent(FlexAlign.Start)
        }
      }, (item: string, index: number) => JSON.stringify(item) + index)
    }
    .width('100%')
    .height('100%')
  }
}
dart 复制代码
import { access, ble } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class BlueToothMgr {

  private TAG: string = "BlueToothTest";

  private static mBlueToothMgr: BlueToothMgr | undefined = undefined;

  private advHandle: number = 0xFF; // default invalid value

  public static Ins(){
    if(!BlueToothMgr.mBlueToothMgr){
      BlueToothMgr.mBlueToothMgr = new BlueToothMgr();
    }
    return BlueToothMgr.mBlueToothMgr;
  }

  // STATE_OFF	0	表示蓝牙已关闭。
  // STATE_TURNING_ON	1	表示蓝牙正在打开。
  // STATE_ON	2	表示蓝牙已打开。
  // STATE_TURNING_OFF	3	表示蓝牙正在关闭。
  // STATE_BLE_TURNING_ON	4	表示蓝牙正在打开LE-only模式。
  // STATE_BLE_ON	5	表示蓝牙正处于LE-only模式。
  // STATE_BLE_TURNING_OFF	6	表示蓝牙正在关闭LE-only模式。

  /**
   * 设置蓝牙访问(开关状态)
   * @param isAccess true: 打开蓝牙
   */
  setBlueToothAccess(isAccess: boolean){
    try {
      if(isAccess){
        console.info(this.TAG, 'bluetooth enableBluetooth 1');
        access.enableBluetooth();
        console.info(this.TAG, 'bluetooth enableBluetooth ');
        access.on('stateChange', (data: access.BluetoothState) => {
          let btStateMessage = this.switchState(data);
          if (btStateMessage == 'STATE_ON') {
            access.off('stateChange');
          }
          console.info(this.TAG, 'bluetooth statues: ' + btStateMessage);
        })
      }else{
        console.info(this.TAG, 'bluetooth disableBluetooth 1');
        access.disableBluetooth();
        console.info(this.TAG, 'bluetooth disableBluetooth ');
        access.on('stateChange', (data: access.BluetoothState) => {
          let btStateMessage = this.switchState(data);
          if (btStateMessage == 'STATE_OFF') {
            access.off('stateChange');
          }
          console.info(this.TAG, "bluetooth statues: " + btStateMessage);
        })
      }
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  private switchState(data: access.BluetoothState){
    let btStateMessage = '';
    switch (data) {
      case 0:
        btStateMessage += 'STATE_OFF';
        break;
      case 1:
        btStateMessage += 'STATE_TURNING_ON';
        break;
      case 2:
        btStateMessage += 'STATE_ON';
        break;
      case 3:
        btStateMessage += 'STATE_TURNING_OFF';
        break;
      case 4:
        btStateMessage += 'STATE_BLE_TURNING_ON';
        break;
      case 5:
        btStateMessage += 'STATE_BLE_ON';
        break;
      case 6:
        btStateMessage += 'STATE_BLE_TURNING_OFF';
        break;
      default:
        btStateMessage += 'unknown status';
        break;
    }
    return btStateMessage;
  }

  /**
   * 主播蓝牙广播
   */
  public registerBroadcast(){
    try {
      ble.on('advertisingStateChange', (data: ble.AdvertisingStateChangeInfo) => {
        console.info(this.TAG, 'bluetooth advertising state = ' + JSON.stringify(data));
        AppStorage.setOrCreate('advertiserState', data.state);
      });
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

  /**
   * 开启蓝牙广播
   */
  public async startBroadcast(valueBuffer: Uint8Array){

    // 表示发送广播的相关参数。
    let setting: ble.AdvertiseSetting = {
      // 表示广播间隔,最小值设置160个slot表示100ms,最大值设置16384个slot,默认值设置为1600个slot表示1s。
      interval: 160,
      // 表示发送功率,最小值设置-127,最大值设置1,默认值设置-7,单位dbm。推荐值:高档(1),中档(-7),低档(-15)。
      txPower: 0,
      // 表示是否是可连接广播,默认值设置为true,表示可连接,false表示不可连接。
      connectable: true
    };

    // BLE广播数据包的内容。
    let manufactureDataUnit: ble.ManufactureData = {
      // 表示制造商的ID,由蓝牙SIG分配。
      manufactureId: 4567,
      manufactureValue: valueBuffer.buffer
    };

    let serviceValueBuffer = new Uint8Array(4);
    serviceValueBuffer[0] = 5;
    serviceValueBuffer[1] = 6;
    serviceValueBuffer[2] = 7;
    serviceValueBuffer[3] = 8;

    // 广播包中服务数据内容。
    let serviceDataUnit: ble.ServiceData = {
      serviceUuid: "00001888-0000-1000-8000-00805f9b34fb",
      serviceValue: serviceValueBuffer.buffer
    };

    // 表示广播的数据包内容。
    let advData: ble.AdvertiseData = {
      serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
      manufactureData: [manufactureDataUnit],
      serviceData: [serviceDataUnit],
      includeDeviceName: false // 表示是否携带设备名,可选参数。注意带上设备名时广播包长度不能超出31个字节。
    };

    // 表示回复扫描请求的响应内容。
    let advResponse: ble.AdvertiseData = {
      serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
      manufactureData: [manufactureDataUnit],
      serviceData: [serviceDataUnit]
    };

    // 首次启动广播设置的参数。
    let advertisingParams: ble.AdvertisingParams = {
      advertisingSettings: setting,
      advertisingData: advData,
      advertisingResponse: advResponse,
      // 	表示发送广播持续的时间。单位为10ms,有效范围为1(10ms)到65535(655350ms),如果未指定此参数或者将其设置为0,则会连续发送广播。
      duration: 0 // 可选参数,若大于0,则广播发送一段时间后,则会临时停止,可重新启动发送
    }

    // 首次启动广播,且获取所启动广播的标识ID
    try {
      this.registerBroadcast();
      this.advHandle = await ble.startAdvertising(advertisingParams);
    } catch (err) {
      console.error(this.TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }

}
相关推荐
张帅涛_6663 小时前
HarmonyOS开发之全局状态管理
华为·harmonyos
让开,我要吃人了3 小时前
HarmonyOS开发实战( Beta5.0)蓝牙实现服务端和客户端通讯详解
开发语言·前端·华为·移动开发·harmonyos·鸿蒙·鸿蒙系统
让开,我要吃人了4 小时前
HarmonyOS应用开发( Beta5.0)HOS-用户认证服务:面部识别
服务器·前端·华为·移动开发·嵌入式·harmonyos·鸿蒙
让开,我要吃人了7 小时前
HarmonyOS开发实战( Beta5.0)橡皮擦案例实践详解
开发语言·前端·华为·移动开发·harmonyos·鸿蒙·鸿蒙系统
ImomoTo7 小时前
HarmonyOS学习(十一)——安全管理
学习·安全·harmonyos·arkts·arkui
爱桥代码的程序媛16 小时前
HarmonyOS开发5.0【应用程序包】
分布式·harmonyos·鸿蒙·鸿蒙系统·openharmony·鸿蒙开发·程序包
爱桥代码的程序媛16 小时前
HarmonyOS开发5.0【rcp网络请求】
网络·移动开发·harmonyos·鸿蒙·鸿蒙系统·openharmony·rcp
让开,我要吃人了16 小时前
HarmonyOS应用开发( Beta5.0)一杯冰美式的时间“拿捏Grid组件”
服务器·前端·华为·移动开发·harmonyos·鸿蒙·openharmony
Android技术栈17 小时前
鸿蒙开发(API 12 Beta6版)【P2P模式】 网络WLAN服务开发
网络·harmonyos·鸿蒙·鸿蒙系统·p2p·openharmony·wlan
Android技术栈18 小时前
鸿蒙(API 12 Beta6版)图形加速【OpenGL ES平台内插模式】超帧功能开发
elasticsearch·harmonyos·鸿蒙·鸿蒙系统·openharmony·图形·超帧