HarmonyOS 鸿蒙Next中如何进行蓝牙开发
HarmonyOS 鸿蒙Next中如何进行蓝牙开发 我的软件需要使用到蓝牙协议,应该怎样去做开发
正文
首先我们需要清楚在鸿蒙当中怎样去实现蓝牙的功能
1.申请蓝牙权限
这里贴上文档地址:向用户申请授权-申请应用权限-应用权限管控-程序访问控制-安全-系统 - 华为HarmonyOS开发者
通过查看华为官方文档我们可以知道申请蓝牙权限有这些步骤:

首先,我们需要在配置文件当中申请蓝牙权限
如图,我们需要在module.json5配置文件中加入这么一个配置
"requestPermissions": [
{
"name" : "ohos.permission.ACCESS_BLUETOOTH",
"reason": "$string:blooth_reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"inuse"
}
}
],

其中reason一项很容易让人搞不懂鼠标移动到reason后,按住control,鼠标左键单击

单击后我们会发现跳转到了string.json,然后在这里仿造格式写上原因就行啦,注意这里name属性对应的就是上面那个配置当中$string:blooth_reason的blooth_reason,这里随意起名字就好,但是要规范,自己能看得懂

在配置文件声明完权限后还需要添加向用户申请权限的代码,代码如下
// 用户申请权限
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) {
// 用户授权,可以继续访问目标操作
}
}
}
需要 申请权限的时候就调用一下 requestBlueToothPermission ,这里要注意因为 requestBlueToothPermission 是异步函数,所以要用await来进行调用,像这样:
await this.requestBlueToothPermission()
这里给点小建议,可以在页面初始化的时候调用这个函数,这样就可以直接获取授权了
在这里我定义了一个init函数

代码如下
async init() {
try {
await this.requestBlueToothPermission()
} catch (err) {
promptAction.showToast({
message: 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message//弹窗内容
});
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
我们可以在页面顶端调用该函数,如图所示:

如果一切顺利打开软件到调用init函数所在页面就会跳出授权弹窗

至此授权的过程也就完成了,如果用户选择拒绝授权还需要涉及二次授权,因为博主也没有二次授权的相关经验,还请大家自行参考官方文档进行调试
这里贴上二次授权的文档地址: 二次向用户申请授权-申请应用权限-应用权限管控-程序访问控制-安全-系统 - 华为HarmonyOS开发者
2.蓝牙相关操作开发
这里我定义了一个模型,用来存储扫描到的蓝牙设备数据,方便在连接界面展示
GlobalBlueTooth.ets
export interface BlueToothItem {
mac: string,
name: string
}
@ObservedV2
export class GlobalBlueTooth {
@Trace blueList: BlueToothItem[] = [] //蓝牙设备数据列表
//重置数据方法
rest()
{
this.blueList = [] //蓝牙设备数据列表
}
}
1.蓝牙开与关
BlueToothManager.ets
//开启蓝牙
async blueToothOn()
{
try {
await this.requestBlueToothPermission()
await access.enableBluetooth();
} catch (err) {
promptAction.showToast({
message: 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message//弹窗内容
});
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
//关闭蓝牙
async blueToothOff()
{
try {
await this.requestBlueToothPermission()
await access.disableBluetooth();
} catch (err) {
promptAction.showToast({
message: 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message//弹窗内容
});
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
2.蓝牙设备的搜索
BlueToothManager.ets
//检查扫描到的设备mac是否重复
//重复则不添加到表中
blueToothDeviceChecker(data: Array<string>)
{
for(let i = 0; i < this.blueToothData.blueList.length; i++)
{
if(this.blueToothData.blueList[i].mac == data[0])
{
//当检查到重复则跳出循环返回0
return 0;
}
}
//当循环结束还没有找到重复则返回1
return 1;
}
//蓝牙搜索方法
// 定义扫描结果上报回调函数
onReceiveEvent = (data: Array<string>) => {
let deviceName = connection.getRemoteDeviceName(data[0])
console.info('bluetooth device: '+ JSON.stringify(data));
if(this.blueToothDeviceChecker(data))
{
//当没有扫描到重复时添加数据
if(deviceName == '')
{
console.info('bluetooth device name: 未知设备');
this.blueToothData.blueList.unshift({
mac: data[0],
name: "未知设备"
}) //在共享的设备数据末位添加一条扫描到的设备数据
}
else
{
console.info('bluetooth device name: '+ deviceName);
this.blueToothData.blueList.unshift({
mac: data[0],
name: deviceName
})
}
}
};
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);
}
}
3.获取本机的扫描模式
BlueToothManager.ets
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);
}
}
4.获取已经配对的设备信息
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);
}
}
5.与设备连接
这里采用的是spp连接的方式,我定义了一个sppClientManager的类来进行管理
SppClientManager.ets
import { socket } from '@kit.ConnectivityKit'
import { BusinessError } from '@kit.BasicServicesKit';
import { GlobalType } from '../models/globalType';
import { AppStorageV2 } from '@kit.ArkUI';
import { connection } from '@kit.NetworkKit';
class SppClientManager {
// 定义客户端的socket id
clientNumber: number = -1;
//共享连接数据
typeData: GlobalType = AppStorageV2.connect(GlobalType, 'TYPE_KEY', () => new GlobalType())!
// 发起连接
public startConnect(peerDevice: string, deviceName: string): void {
// 配置连接参数
let option: socket.SppOptions = {
uuid: '00001101-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 {
//连接成功
this.typeData.connectType = 1; //修改显示的连接状态
this.typeData.connectedDeviceName = deviceName; //修改显示的连接设备名称
console.info('startConnect clientNumber: ' + num);
this.clientNumber = num;
}
});
console.info('startConnect after ' + peerDevice);
}
// 发送数据
public sendData(sendData: number) {
console.info('sendData ' + this.clientNumber);
let arrayBuffer = new ArrayBuffer(1);
let data = new Uint8Array(arrayBuffer);
data[0] = sendData;
try {
socket.sppWrite(this.clientNumber, arrayBuffer);
} catch (err) {
console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
return -1; //发现异常,也就是有可能断开连接就返回-1
}
return 1; //正常发送数据代表还在连接就返回1
}
// 定义接收数据的回调函数
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);
}
}
}
export const sppClientManager: SppClientManager = new SppClientManager()
BlueToothManager.ets
public connectDevice(device: string) {
let pairState = connection.getPairState(device); //查询设备是否配对
if(pairState == 2)
{
//设备已配对
let deviceName = connection.getRemoteDeviceName(device); //获取设备名称
sppClientManager.startConnect(device, deviceName) //发起连接
}
else
{
//设备没有配对
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);
console.info('mac:' + device);
}
}
}
当连接设备的时候调用connectDevice函数,传入连接设备的地址一般为 XX:XX:XX:XX:XX:XX ,该地址可以在步骤二蓝牙设备的搜索当中获取
connectDevice函数会先检查该地址设备是否已配对,如果没有配对则会开始配对设备,如果已配对就会调用SppClientManager类中的startConnect开始连接设备,连接成功后就可以开始收发数据了
6.数据的收发
SppClientManager.ets
// 发送数据
public sendData(sendData: number) {
console.info('sendData ' + this.clientNumber);
let arrayBuffer = new ArrayBuffer(1);
let data = new Uint8Array(arrayBuffer);
data[0更多关于HarmonyOS 鸿蒙Next中如何进行蓝牙开发的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中进行蓝牙开发,需使用ArkTS语言调用蓝牙API。主要步骤包括:1. 申请蓝牙权限(ohos.permission.USE_BLUETOOTH等);2. 初始化蓝牙模块(bluetooth.getLocalState);3. 发现与配对设备(startBluetoothDiscovery);4. 建立GATT连接(connectGatt);5. 通过特征值(characteristic)进行数据读写。开发过程需遵循HarmonyOS蓝牙规范,使用系统提供的Profile和Service。
在HarmonyOS Next中进行蓝牙开发,主要使用@ohos.bluetooth和@ohos.bluetoothManager等系统接口。核心流程如下:
1. 权限与配置
- 在
module.json5中声明必要权限,例如:
"requestPermissions": [
{
"name": "ohos.permission.USE_BLUETOOTH",
"reason": "用于蓝牙通信"
},
{
"name": "ohos.permission.LOCATION",
"reason": "用于蓝牙设备发现"
}
]
2. 基础蓝牙操作
- 启用/禁用蓝牙:通过
bluetoothManager.enableBluetooth()/disableBluetooth()控制。 - 设备可见性:使用
bluetoothManager.setBluetoothScanMode()设置可被发现模式。 - 本地设备信息:通过
bluetoothManager.getLocalName()等获取。
3. 经典蓝牙开发
- 设备发现:调用
bluetoothManager.startBluetoothDiscovery()扫描设备,通过订阅bluetoothDeviceFind事件获取设备列表。 - 配对与连接:使用
bluetoothManager.pairDevice()配对,通过socket.construct()创建Socket进行RFCOMM通信。 - 数据传输:基于Socket的
send()/recv()方法实现。
4. 低功耗蓝牙开发
- 中心设备模式:
- 通过
bluetooth.BLE.createGattClientDevice()创建客户端。 - 连接后使用
connect()建立链路,通过discoverServices()发现服务。 - 通过
readCharacteristicValue()/writeCharacteristicValue()读写特征值,订阅characteristicChange事件接收通知。
- 通过
- 外围设备模式:
- 使用
bluetooth.BLE.createGattServerDevice()创建服务端。 - 通过
addService()添加服务,使用startAdvertising()广播。
- 使用
5. 关键注意事项
- 确保在
onDestroy()等生命周期中释放资源,停止扫描、断开连接。 - 涉及UI更新的操作需通过主线程处理。
- 低功耗蓝牙操作需注意连接参数和MTU设置。
建议参考官方文档中的蓝牙相关指南和API详解,并利用DevEco Studio提供的模拟器或真机进行调试。

