-
手表支持低功耗蓝牙开发:具体的机型参考机型列表HarmonyOS 5.1 支持机型
-
低功耗蓝牙开发连接和传输数据代码示例: 客户端:
import { ble, constant } from '[@kit](/user/kit).ConnectivityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
const TAG: string = 'GattClientManager';
export class GattClientManager {
device: string = '';
gattClient: ble.GattClientDevice | undefined = undefined;
connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
// 标准协议描述符Client Characteristic Configuration,用于特征值变化通知或指示
myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB';
// 自定义描述符
mySecondDescriptorUuid: string = '00008888-0000-1000-8000-00805F9B34FB';
myService: ble.GattService | undefined = undefined;
myCharacteristic: ble.BLECharacteristic | undefined = undefined;
myFirstDescriptor: ble.BLEDescriptor | undefined = undefined;
mySecondDescriptor: ble.BLEDescriptor | undefined = undefined;
foundService: boolean = false;
foundChar: boolean = false;
foundFirstDes: boolean = false;
foundSecondDes: boolean = false;
// 构造BLEDescriptor
private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
let descriptor: ble.BLEDescriptor = {
serviceUuid: this.myServiceUuid,
characteristicUuid: this.myCharacteristicUuid,
descriptorUuid: des,
descriptorValue: value
};
return descriptor;
}
// 构造BLECharacteristic
private initCharacteristic(isWrite: boolean): ble.BLECharacteristic {
let descriptors: Array<ble.BLEDescriptor> = [];
let charBuffer = new ArrayBuffer(2);
if (isWrite) {
let charValue = new Uint8Array(charBuffer);
charValue[0] = 21;
charValue[1] = 22;
}
let characteristic: ble.BLECharacteristic = {
serviceUuid: this.myServiceUuid,
characteristicUuid: this.myCharacteristicUuid,
characteristicValue: charBuffer,
descriptors: descriptors
};
return characteristic;
}
private logCharacteristic(char: ble.BLECharacteristic) {
let message = 'logCharacteristic uuid:' + char.characteristicUuid + ', value: ';
let value = new Uint8Array(char.characteristicValue);
message += 'logCharacteristic value: ';
for (let i = 0; i < char.characteristicValue.byteLength; i++) {
message += value[i] + ' ';
}
console.info(TAG, message);
}
private logDescriptor(des: ble.BLEDescriptor) {
let message = 'logDescriptor uuid:' + des.descriptorUuid + ', value: ';
let value = new Uint8Array(des.descriptorValue);
message += 'logDescriptor value: ';
for (let i = 0; i < des.descriptorValue.byteLength; i++) {
message += value[i] + ' ';
}
console.info(TAG, message);
}
private checkService(services: Array<ble.GattService>) {
for (let i = 0; i < services.length; i++) {
if (services[i].serviceUuid != this.myServiceUuid) {
continue;
}
this.myService = services[i];
this.foundService = true;
for (let j = 0; j < services[i].characteristics.length; j++) {
if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) {
continue;
}
this.logCharacteristic(services[i].characteristics[j]);
this.myCharacteristic = services[i].characteristics[j];
this.foundChar = true;
for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) {
if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) {
this.myFirstDescriptor= services[i].characteristics[j].descriptors[k];
this.foundFirstDes = true;
continue;
}
if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.mySecondDescriptorUuid) {
this.mySecondDescriptor = services[i].characteristics[j].descriptors[k];
this.foundSecondDes = true;
continue;
}
}
}
}
console.info(TAG, 'foundService: ' + this.foundService + ', foundChar: ' + this.foundChar +
', foundFirDes: ' + this.foundFirstDes + ', foundSecDes: ' + this.foundedSecondDes);
}
// 1. 定义连接状态变化回调函数
onGattClientStateChange = (stateInfo: ble.BLEConnectionChangeState) => {
let state = '';
switch (stateInfo.state) {
case 0:
state = 'DISCONNECTED';
break;
case 1:
state = 'CONNECTING';
break;
case 2:
state = 'CONNECTED';
break;
case 3:
state = 'DISCONNECTING';
break;
default:
state = 'undefined';
break;
}
console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state);
if (stateInfo.deviceId == this.device) {
this.connectState = stateInfo.state;
}
};
// 2. client端主动连接时调用
public startConnect(peerDevice: string) { // 对端设备一般通过ble查找设备获取到
if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) {
console.error(TAG, 'startConnect failed');
return;
}
console.info(TAG, 'startConnect ' + peerDevice);
this.device = peerDevice;
// 2.1 使用device构造gattClient,后续的交互都需要使用该实例
this.gattClient = ble.createGattClientDevice(peerDevice);
try {
// 2.2 订阅连接状态
this.gattClient.on('BLEConnectionStateChange', this.onGattClientStateChange);
// 2.3 发起连接
this.gattClient.connect();
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 3. client端连接成功后,需要进行服务发现
public async discoverServices() {
if (!this.gattClient) {
console.error(TAG, 'gattClient does not exist');
return;
}
console.info(TAG, 'discoverServices');
try {
let serverService = await this.gattClient.getServices();
this.checkService(serverService); // 要确保server端的服务内容有业务所需要的服务
if (typeof this.myService !== 'undefined') {
console.info(TAG, 'Service: ' + JSON.stringify(this.myService));
}
if (typeof this.myCharacteristic !== 'undefined') {
this.logCharacteristic(this.myCharacteristic);
}
if (typeof this.myFirstDescriptor !== 'undefined') {
this.logDescriptor(this.myFirstDescriptor);
}
if (typeof this.mySecondDescriptor !== 'undefined') {
this.logDescriptor(this.mySecondDescriptor);
}
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 4. 在确保拿到了server端的服务结果后,读取server端特定服务的特征值时调用
public readCharacteristicValue() {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundChar) { // 要确保server端有对应的characteristic
console.error(TAG, 'server characteristic does not exist');
return;
}
let characteristic = this.initCharacteristic(false);
console.info(TAG, 'readCharacteristicValue');
try {
this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => {
this.myCharacteristic = outData;
this.logCharacteristic(this.myCharacteristic);
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 5. 在确保拿到了server端的服务结果后,写入server端特定服务的特征值时调用
public writeCharacteristicValue() {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundChar) { // 要确保server端有对应的characteristic
console.error(TAG, 'server characteristic does not exist');
return;
}
let characteristic = this.initCharacteristic(true);
console.info(TAG, 'writeCharacteristicValue');
try {
this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => {
if (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
return;
}
console.info(TAG, 'writeCharacteristicValue success');
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 6. 在确保拿到了server端的服务结果后,读取server端特定服务的描述符时调用
public readDescriptorValue() {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundSecondDes) { // 要确保server端有对应的descriptor
console.error(TAG, 'server descriptor does not exist');
return;
}
let descBuffer = new ArrayBuffer(0);
let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
console.info(TAG, 'readDescriptorValue');
try {
this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => {
this.logDescriptor(outData);
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 7. 在确保拿到了server端的服务结果后,写入server端特定服务的描述符时调用
public writeDescriptorValue() {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundSecondDes) { // 要确保server端有对应的descriptor
console.error(TAG, 'server descriptor does not exist');
return;
}
let descBuffer = new ArrayBuffer(2);
let descValue = new Uint8Array(descBuffer);
descValue[0] = 41;
descValue[1] = 42;
let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
console.info(TAG, 'writeDescriptorValue');
try {
this.gattClient.writeDescriptorValue(descriptor, (err) => {
if (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
return;
}
console.info(TAG, 'writeDescriptorValue success');
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 8. 定义特征值变化回调函数
onCharacteristicChange = (char: ble.BLECharacteristic) => {
console.info(TAG, 'onCharacteristicChange: uuid: ' + char.characteristicUuid + ', value: ' + JSON.stringify(new Uint8Array(char.characteristicValue)));
this.myCharacteristic = char;
this.logCharacteristic(this.myCharacteristic);
}
// 9. 使能或禁用接收服务端端特征值内容变更通知的能力时调用,一般通知或者指示,二选一
public Notify(enable: boolean) {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundFirstDes) { // 要确保server端有对应的client configuration descriptor
console.error(TAG, 'server client configuration descriptor does not exist');
return;
}
console.info(TAG, 'Notify ' + this.device + ' enable: ' + enable);
try {
// 订阅特征值变化
this.gattClient.on('BLECharacteristicChange', this.onCharacteristicChange);
// 设置特征值变化通知能力,enable: true表示启用,false表示禁用
this.gattClient.setCharacteristicChangeNotification(this.myCharacteristic, enable, (err: BusinessError) => {
if (err) {
console.error('setCharacteristicChangeNotification callback failed');
} else {
console.info('setCharacteristicChangeNotification callback successful');
}
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 10. 使能或禁用接收服务端端特征值内容变更指示的能力时调用,一般通知或者指示,二选一
public Indicate(enable: boolean) {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
if (!this.foundFirstDes) { // 要确保server端有对应的client configuration descriptor
console.error(TAG, 'server client configuration descriptor does not exist');
return;
}
console.info(TAG, 'Indicate ' + this.device + ' enable: ' + enable);
try {
// 订阅特征值变化
this.gattClient.on('BLECharacteristicChange', this.onCharacteristicChange);
// 设置特征值变化指示能力,enable: true表示启用,false表示禁用
this.gattClient.setCharacteristicChangeIndication(this.myCharacteristic, enable, (err: BusinessError) => {
if (err) {
console.error('setCharacteristicChangeIndication callback failed');
} else {
console.info('setCharacteristicChangeIndication callback successful');
}
});
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
// 11.client端主动断开时调用
public stopConnect() {
if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
console.error(TAG, 'gattClient does not exist or state not connected');
return;
}
console.info(TAG, 'stopConnect ' + this.device);
try {
this.gattClient.disconnect(); // 11.1 断开连接
this.gattClient.off('BLEConnectionStateChange', this.onGattClientStateChange); // 11.2 取消订阅连接状态
this.gattClient.off('BLECharacteristicChange', this.onCharacteristicChange); // 11.3 取消订阅特征值变化
this.gattClient.close() // 11.4 如果应用不再使用此gattClient,则需要close
} catch (err) {
console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
}
let gattClientManager = new GattClientManager();
export default gattClientManager as GattClientManager;
服务端:
import { ble, constant } from '[@kit](/user/kit).ConnectivityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
const TAG: string = 'GattServerManager';
export class GattServerManager {
device = '';
gattServer: ble.GattServer | undefined = undefined;
connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
// 标准协议描述符Client Characteristic Configuration,用于特征值变化通知或指示
myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34
更多关于HarmonyOS 鸿蒙Next低功耗蓝牙开发的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS智能手表支持低功耗蓝牙(BLE)开发
HarmonyOS通过@kit.ConnectivityKit模块提供完整的BLE API,支持BLE 5.3协议及扩展广播功能,可满足智能手表与健康设备(如心率带、体脂秤)的数据交互需求。
文档参考地址
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/connectivity-api
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
智能手表完全支持低功耗蓝牙(BLE)开发
@ohos.bluetooth.ble (蓝牙ble模块) 提供了基于低功耗蓝牙(Bluetooth Low Energy)技术的蓝牙能力,支持发起BLE扫描、发送BLE广播报文、以及基于通用属性协议(Generic Attribute Profile,GATT)的连接和传输数据。
参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-bluetooth-ble
鸿蒙Next低功耗蓝牙开发基于HarmonyOS分布式能力,使用@ohos.bluetooth低功耗API。主要接口包括GattClient和GattServer,支持设备扫描、连接、服务发现及数据读写。需声明ohos.permission.USE_BLUETOOTH权限,遵循BLE协议规范进行数据传输。开发时注意设备适配和功耗优化。