
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區(qū)??
??https://ost.51cto.com??
OpenHarmony BLE藍牙設備連接
1、簡介
OpenHarmony藍牙模塊提供了基礎的傳統藍牙能力以及BLE的掃描、廣播等功能,這里將介紹如何通過OpenHarmony提供的@ohos.bluetooth (藍牙接口)打開當前設備的藍牙,關閉藍牙,以及連接BLE藍牙設備。
2、設備與環(huán)境
- 設備:九聯s905l3a機頂盒、開鴻智谷學生卡BLE藍牙設備
- 系統:OpenHarmony 3.2 beta2
- SDK:9
演示視頻:??OpenHarmony BLE藍牙設備連接??
3、邏輯流程

首先機頂盒在開始的時候獲取藍牙相關權限,然后通過OpenHarmony提供的藍牙接口打開藍牙,接著訂閱發(fā)現BLE設備發(fā)現事件,然后通過OpenHarmony提供的藍牙接口開啟BLE設備掃描,當發(fā)現到了BLE藍牙設備后,進行上報,BLE設備發(fā)現事件觸發(fā),獲取到來自BLE設備的廣播信息包,然后進行BLE藍牙連接。
4、實現過程
(1)獲取藍牙相關權限
在使用藍牙接口之前,首先要讓設備獲取一下權限:
- ohos.permission.USE_BLUETOOTH // 允許應用查看藍牙的配置。
- ohos.permission.DISCOVER_BLUETOOTH // 允許應用配置本地藍牙,查找遠端設備且與之配對連接。
- ohos.permission.LOCATION // 允許應用獲取設備位置信息。
- ohos.permission.MANAGE_BLUETOOTH // 允許應用配對藍牙設備,并對設備的電話簿或消息進行訪問。
打開DevEco Studio 3.1.0.200,創(chuàng)建新的Stage項目,在項目中的module.json文件中添加相關權限:
"requestPermissions": [
{
"name": "ohos.permission.USE_BLUETOOTH",
"reason": "$string:grant_use_bluetooth",
"usedScene": {
"abilities": [
"MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.DISCOVER_BLUETOOTH",
"reason": "$string:grant_discovery_bluetooth",
"usedScene": {
"abilities": [
"MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:grant_location",
"usedScene": {
"abilities": [
"MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.MANAGE_BLUETOOTH",
"reason": "$string:grant_manage_bluetooth",
"usedScene": {
"abilities": [
"MainAbility"
],
"when": "inuse"
}
}
]
(2)打開設備的藍牙
首先,通過調用 bluetooth.getState() 藍牙接口來獲取當前設備藍牙是否打開,并設置藍牙開關的標識位 isOn。
async aboutToAppear() {
// 等待獲取藍牙權限
await globalThis.abilityContext.requestPermissionsFromUser(['ohos.permission.USE_BLUETOOTH', 'ohos.permission.DISCOVER_BLUETOOTH', 'ohos.permission.LOCATION', 'ohos.permission.MANAGE_BLUETOOTH'])
logger.info(TAG, `獲取權限 grantPermission,requestPermissionsFromUser,PermissionRequestResult`)
// 獲取藍牙狀態(tài)
let state = bluetooth.getState()
// 判斷當前設備藍牙是否打開
if (state === bluetooth.BluetoothState.STATE_ON) {
this.isOn = true
}
if (state === bluetooth.BluetoothState.STATE_OFF) {
this.isOn = false
}
}
如果當前設備藍牙未打開,則通過調用 bluetooth.enableBluetooth() 藍牙接口來打開藍牙。
// 打開藍牙函數
initBluetooth() {
this.enable = bluetooth.enableBluetooth()
// 判斷藍牙是否成功打開
if(this.enable==true){
prompt.showToast({
message: 'Open bluetooth ' + this.enable,
duration: 2000,
});
}
}
(3)注冊發(fā)現BLE設備監(jiān)聽器
在設備打開藍牙之后,通過調用 bluetooth.BLE.on('BLEDeviceFind') 藍牙接口來訂閱BLE設備發(fā)現上報事件。該接口參數如下:

通過注冊發(fā)現BLE設備監(jiān)聽器,可以得到發(fā)現設備的集合,BLE設備的廣播包、地址、信號強度rssi,在這里發(fā)現獲取連接BLE設備名字的接口 getDeviceName 無法成功調用,所以自己通過解析廣播包來獲取設備名字。
// 訂閱BLE設備發(fā)現上報事件
// 獲取到的data包括BLE設備的廣播包、地址、信號強度rssi
bluetooth.BLE.on('BLEDeviceFind', (data) => {
logger.info(TAG, `enter on bluetoothBLEDeviceFind`)
logger.info("rgytl 開始掃描設備地址! 1")
if (data !== null && data.length > 0) {
logger.info("rgytl 開始掃描設備地址! 2")
if (this.discoveryBleList.indexOf(data[0]) === -1) {
// 把發(fā)現的設備地址存入列表
this.discoveryBleList.push(data[0].deviceId)
logger.info("rgytl ---- discoveryBleList = "+JSON.stringify(this.discoveryBleList))
// 讀取廣播包,解析廣播包,得到設備名字,并存入設備列表
var i = 0;
var x = data[0].data[i]
var y = data[0].data[i + 1]
while(y!=0x09 && i+x+2<data[0].data.byteLength){
i = i+x+1
x = data[0].data[i]
y = data[0].data[i+1]
}
let arr = data[0].data.slice(i+2,i+x+1)
var BLEName = ""
for(let j=0;j<arr.byteLength;j++){
BLEName+=String.fromCharCode(arr[j])
}
logger.info("rgytl ---- discoveryBleList = "+BLEName)
// 把通過廣播包解析的BLE設備名字存入設備名字列表
this.BleInfo.push(BLEName)
// 把發(fā)現的BLE設備信號存入設備信號強度列表
this.BleRssi.push(data[0].rssi)
logger.info("rgytl ---- discoveryBleList = "+data[0].rssi)
}
logger.info(TAG, `開啟掃描 discoveryBleList = ${JSON.stringify(this.discoveryBleList)}`)
}
})
(4)開啟BLE設備掃描
在完成訂閱BLE設備發(fā)現上報事件后,通過調用 bluetooth.BLE.startBLEScan 接口去開啟BLE設備掃描,通過該接口,可以對掃描BLE設備進行過濾,可以過濾的參數有:BLE設備的地址、名字、以及服務的UUID等。

在這里,我設置只掃描包含我BLE設備名字的BLE設備,這樣子就不會說掃描到一大堆其他的BLE設備,影響使用,只需要開啟一次掃描和訂閱一次BLE設備發(fā)現上報事件就可以了,使用的時候只要沒有關閉,就不需要重復調用。
// 設置藍牙BLE掃描模式(根據名字掃描)
bluetooth.BLE.startBLEScan(
[{
deviceId: null,
name: "ble slave test",
serviceUuid: null
}],
{
interval: 0,
dutyMode: bluetooth.ScanDuty.SCAN_MODE_LOW_POWER,
matchMode: bluetooth.MatchMode.MATCH_MODE_AGGRESSIVE,
}
)
(5)連接BLE設備
在掃描到BLE設備之后,可以通過 on(‘BLEConnectionStateChange’) 來訂閱獲取BLE設備的連接狀態(tài)變化事件,在使用該接口之前,要先通過 bluetooth.BLE.createGattClientDevice('XX:XX:XX:XX:XX:XX') 接口創(chuàng)建一個可使用的GattClientDevice實例。

// 訂閱BEL狀態(tài)變化
if(this.BleOnflag){
// 只創(chuàng)建一個GattClient對象
this.BleOnflag = false
this.BLEDevice = bluetooth.BLE.createGattClientDevice(item);
// 訂閱獲取BLE設備的連接狀態(tài)變化事件
this.BLEDevice.on('BLEConnectionStateChange', (data) => {
console.log('bluetooth connectState state changed');
let connectState = data.state;
// 根據不通的連接狀態(tài),提示不同的信息
if(JSON.stringify(connectState) == 0){
logger.info(`connectState = ${JSON.stringify(connectState)},斷開連接`)
prompt.showToast({
message: '斷開連接',
duration: 2000,
});
} else if(JSON.stringify(connectState) == 2){
logger.info(`connectState = ${JSON.stringify(connectState)},連接成功`)
prompt.showToast({
message: '連接成功',
duration: 2000,
});
} else if(JSON.stringify(connectState) == 1){
logger.info(`connectState = ${JSON.stringify(connectState)},正在連接`)
} else {
logger.info(`connectState = ${JSON.stringify(connectState)},正在斷連`)
}
logger.info(`connectState = ${JSON.stringify(connectState)}`);
})
}
在前面通過 bluetooth.BLE.createGattClientDevice(item) 創(chuàng)建一個GattClientDevice實例 BLEDevice 后,我們可以通過該實例去調用 connect() 方法連接BLE設備。注意,GattClientDevice實例 只需要創(chuàng)建一個就可以。

// 連接藍牙
let BLEConnect = this.BLEDevice.connect()
// 如果連接成功,則把BLE設備存入連接成功列表
if(BLEConnect){
this.deviceBleList.push(item)
}
(6)結尾處理
當不連接BLE設備的時候,要記得關閉BLE設備掃描,取消訂閱設備發(fā)現事件。
取消BLE設備連接,通過之前創(chuàng)建的GattClientDevice實例 BLEDevice 調用 disconnect() 方法斷開連接BLE設備。
Button("斷開")
.alignSelf(ItemAlign.Center)
.onClick(() => {
AlertDialog.show({
title: $r('app.string.disconnect'),
message: '此操作將會斷開該設備的連接',
primaryButton: {
value: $r('app.string.cancel'),
action: () => {
}
},
secondaryButton: {
value: $r('app.string.confirm'),
action: () => {
// 斷開連接BLE設備
let BLEdisConnect = this.BLEDevice.disconnect()
if(BLEdisConnect){
logger.info(`connectState BLEdisConnect = ${JSON.stringify(BLEdisConnect)},斷開連接`)
// 移出BLE設備連接列表
this.deviceBleList.pop(item)
}
}
}
})
})
在斷開連接、關閉藍牙之后,可以通過 off(‘connectStateChange’) 取消訂閱BLE連接狀態(tài)變化事件、bluetooth.BLE.stopBLEScan 停止BLE掃描、以及 bluetooth.BLE.off(‘BLEDeviceFind’) 取消訂閱BLE設備發(fā)現上報事件,最后通過 bluetooth.disableBluetooth() 關閉藍牙。
.onChange((isOn: boolean) => {
if (isOn) {
this.isOn = true
this.initBluetooth()
} else {
this.isOn = false
bluetooth.BLE.off('BLEDeviceFind',()=>{
logger.info("rgytl 取消BLE設備發(fā)現訂閱!")
})
bluetooth.BLE.stopBLEScan()
this.disable = bluetooth.disableBluetooth()
this.discoveryList = []
this.BleInfo = []
this.BleRssi = []
if(this.disable==true){
prompt.showToast({
message: 'Close bluetooth ' + this.disable,
duration: 2000,
});
}
}
})
5、參考文檔
??OpenAtom OpenHarmony 藍牙??
??應用權限列表??
??OpenHarmony Gitee 藍牙??
文章相關附件可以點擊下面的原文鏈接前往下載
??https://ost.51cto.com/resource/2700??
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區(qū)??
??https://ost.51cto.com??