鴻蒙藍牙通信

https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-bluetooth-low-energy

藍牙權限

module.json5

{"module": {"requestPermissions": [{"name": "ohos.permission.ACCESS_BLUETOOTH","reason": "$string:app_name","usedScene": {"when": "inuse"}}],}
}

藍牙管理工具類

  1. 申請藍牙權限 (requestPermission)
    ○ 使用@kit.AbilityKit中的權限管理模塊創建AtManager實例。
    ○ 請求用戶授權ohos.permission.ACCESS_BLUETOOTH權限。
    ○ 如果用戶拒絕,則跳轉到設置界面讓用戶授權。
    ○ 異常時通過promptAction顯示錯誤信息。
  2. 檢查藍牙權限 (checkPermission)
    ○ 獲取當前應用的Bundle信息。
    ○ 檢查是否已授予藍牙權限。
    ○ 返回布爾值,表示權限是否被授予。
  3. 檢查藍牙開關狀態 (checkOpen)
    ○ 使用@kit.ConnectivityKit的access模塊獲取藍牙狀態。
    ○ 返回布爾值,表示藍牙是否開啟(返回access.BluetoothState.STATE_ON即開啟)。
  4. 掃描藍牙設備 (scanDevice)
    ○ 啟動藍牙掃描,設置掃描間隔、掃描模式等參數。
    ○ 監聽BLEDeviceFind事件,收集掃描到的設備并去重。
    ○ 通過回調函數將掃描結果數組返回給調用者。
    ○ 設置10秒超時自動停止掃描。
  5. 連接藍牙設備 (connectDevice)
    ○ 根據設備ID創建GATT客戶端設備實例。
    ○ 連接設備,并監聽連接狀態變化事件。
    ○ 當連接成功(狀態變為STATE_CONNECTED)時,執行回調函數并顯示成功提示,同時調用listenChange方法開啟通知監聽。
  6. 斷開藍牙連接 (disconnectDevice)
    ○ 如果存在連接,斷開并關閉GATT客戶端設備,重置引用。
    ○ 顯示斷開提示。
  7. 發送數據 (sendData)
    ○ 向已連接設備寫入數據。
    ○ 查找UUID以0000AE30開頭的服務,然后在該服務下查找UUID以0000AE10開頭的特征。
    ○ 將JSON格式的數據編碼為Uint8Array并寫入特征值。
  8. 開啟通知監聽 (listenChange方法)
    ○ 在連接成功后調用,用于監聽特征值變化(通知)。
    ○ 監聽BLECharacteristicChange事件,接收到數據時解析為BlueData結構。
    ○ 如果數據命令為wifi,則顯示接收到的數據。
    ○ 查找UUID以0000AE30開頭的服務,然后查找UUID以0000AE04開頭的特征,并啟用該特征的通知。

blueManager.ets

import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit' // 導入能力訪問控制相關模塊
import { promptAction } from '@kit.ArkUI' // 導入用戶界面交互模塊
import { access, ble, constant } from '@kit.ConnectivityKit' // 導入藍牙相關功能模塊
import { util } from '@kit.ArkTS' // 導入文本編碼工具
import { emitter } from '@kit.BasicServicesKit'// 1. 藍牙開門 2. 配置設備 wifi 連網
interface BlueData {status?: 200 | 400 //  200 成功  400 失敗msg?: string // 消息提示command?: 'open' | 'wifi' // 命令類型:開門或配置Wi-Fidata?: string[] // 例如配置Wi-Fi時的數據:[ssid, pwd]
}class BlueManager {// 1. 申請藍牙權限async requestPermission() {try {const AtManager = abilityAccessCtrl.createAtManager() // 創建權限管理器實例const res =await AtManager.requestPermissionsFromUser(getContext(), ['ohos.permission.ACCESS_BLUETOOTH']) // 向用戶請求藍牙權限if (res.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { // 如果權限被拒絕await AtManager.requestPermissionOnSetting(getContext(), ['ohos.permission.ACCESS_BLUETOOTH']) // 在設置中請求權限}} catch (e) {promptAction.showToast({ message: JSON.stringify(e) }) // 顯示錯誤信息}}// 2. 檢測藍牙權限checkPermission() {const bundleInfo =bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION) // 獲取當前應用的bundle信息const AtManager = abilityAccessCtrl.createAtManager() // 創建權限管理器實例const grantStatus =AtManager.checkAccessTokenSync(bundleInfo.appInfo.accessTokenId, 'ohos.permission.ACCESS_BLUETOOTH') // 檢查藍牙權限狀態return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED // 返回權限是否被授予}// 3. 檢測藍牙開關checkOpen() {return access.getState() === access.BluetoothState.STATE_ON // 檢查藍牙是否開啟}timeoutID: number = 0 // 掃描超時ID,用于控制掃描時長// 4. 掃描藍牙設備scanDevice(callback: (res: ble.ScanResult[]) => void) {try {clearTimeout(this.timeoutID) // 清除之前的超時設置const scanList: ble.ScanResult[] = [] // 初始化掃描結果列表// 監聽藍牙設備發現事件ble.on('BLEDeviceFind', (res: ble.ScanResult[]) => {scanList.push(...res.filter(v => !scanList.some(vv => v.deviceId === vv.deviceId))) // 過濾重復設備并更新掃描列表callback(scanList) // 調用回調函數傳遞掃描結果})// 開始藍牙掃描ble.startBLEScan(null, {interval: 500, // 設置掃描間隔時間為500毫秒dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER, // 設置低功耗掃描模式matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE // 設置積極匹配模式})this.timeoutID = setTimeout(() => {ble.stopBLEScan() // 停止掃描ble.off('BLEDeviceFind') // 停止監聽藍牙設備發現事件}, 10000)} catch (e) {promptAction.showToast({ message: JSON.stringify(e) }) // 顯示錯誤信息}}currentClient: ble.GattClientDevice | null = null // 當前連接的藍牙客戶端設備// 5. 連接藍牙設備connectDevice(deviceId: string, callback?: () => void) {if (deviceId) {this.currentClient = ble.createGattClientDevice(deviceId) // 創建Gatt客戶端設備實例this.currentClient.connect() // 連接到藍牙設備this.currentClient.on('BLEConnectionStateChange', async (res) => {if (res.state === constant.ProfileConnectionState.STATE_CONNECTED) { // 如果連接狀態為已連接callback?.() // 調用回調函數promptAction.showToast({ message: '藍牙連接成功' }) // 顯示連接成功提示// 監聽特征值變化this.listenChange()}})}}// 6. 斷開藍牙連接disconnectDevice() {if (this.currentClient) {this.currentClient.disconnect() // 斷開藍牙連接this.currentClient.close() // 關閉客戶端設備this.currentClient = null // 重置當前客戶端設備為nullpromptAction.showToast({ message: '藍牙已斷開' }) // 顯示斷開連接提示}}// 7. 發送數據async sendData(data: BlueData) {try {if (this.currentClient) {const list = await this.currentClient.getServices() // 獲取藍牙設備的所有服務const doorService = list.find(v => v.serviceUuid.startsWith('0000AE30')) // 查找門控服務const message = doorService?.characteristics.find(v => v.characteristicUuid.startsWith('0000AE10')) // 查找門控特征值const encoder = new util.TextEncoder() // 創建文本編碼器const u8a = encoder.encodeInto(JSON.stringify(data)) // 將數據編碼為Uint8Array// 寫入特征值await this.currentClient.writeCharacteristicValue({serviceUuid: message?.serviceUuid,characteristicUuid: message?.characteristicUuid,characteristicValue: u8a.buffer,descriptors: [],}, ble.GattWriteType.WRITE)}} catch (e) {promptAction.showToast({ message: JSON.stringify(e) }) // 顯示錯誤信息}}// 8. 監聽特征值變化async listenChange() {if (this.currentClient) {// 注冊特征值變化事件監聽器this.currentClient?.on('BLECharacteristicChange', (res) => {// 創建文本解碼器const decoder = util.TextDecoder.create()// 將特征值數據轉換為Uint8Arrayconst buffer = new Uint8Array(res.characteristicValue)// 將Uint8Array解碼為字符串并解析為JSON對象const result = JSON.parse(decoder.decodeToString(buffer)) as BlueData// 判斷命令類型是否為wifiif (result.command === 'wifi') {// 觸發wifi連接事件,并傳遞狀態信息promptAction.showToast({ message: JSON.stringify(result, null, 2) })}})// 獲取藍牙設備的服務列表const serviceList = await this.currentClient?.getServices()// 查找門控服務const doorService = serviceList?.find(v => v.serviceUuid.startsWith('0000AE30'))// 查找門控特征值const message = doorService?.characteristics.find(v => v.characteristicUuid.startsWith('0000AE04'))// 啟用特征值變化通知await this.currentClient?.setCharacteristicChangeNotification(message, true)}}
}export const blueManager = new BlueManager() // 導出BlueManager實例

藍牙測試頁面

Test.ets

import { blueManager } from '../utils/blueManager'
import { ble } from '@kit.ConnectivityKit'@Entry
@Component
struct Index {@State isPermission: boolean = false@State isOpen: boolean = false@State list: ble.ScanResult[] = []aboutToAppear(): void {this.checkPermission()this.checkOpen()}checkPermission() {this.isPermission = blueManager.checkPermission()}checkOpen() {this.isOpen = blueManager.checkOpen()}build() {Column({ space: 10 }) {Button('申請藍牙權限').onClick(async () => {await blueManager.requestPermission()this.checkPermission()})Button('檢測藍牙權限是否開啟:' + this.isPermission).onClick(() => {this.isPermission = blueManager.checkPermission()})Button('檢測藍牙開關是否開啟:' + this.isOpen).onClick(() => {this.isOpen = blueManager.checkOpen()})Button('掃描藍牙設備').onClick(() => {blueManager.scanDevice((res) => {this.list = res})})List({ space: 5 }) {ForEach(this.list, (item: ble.ScanResult) => {if (item.deviceName) {ListItem() {Row() {Text(item.deviceName)Button('連接藍牙').size({ height: 30 }).onClick(() => {blueManager.connectDevice(item.deviceId)})}}}})}.width('100%').height(300)Button('斷開藍牙連接').onClick(() => {blueManager.disconnectDevice()})Button('發送數據-解鎖開門').onClick(() => {blueManager.sendData({command: 'open'})})Button('發送數據-配網').onClick(() => {blueManager.sendData({command: 'wifi',data: ['Megasu_iPhone', 'nideshengri'] // 寫入自己的 WIFI 和 密碼})})}.height('100%').width('100%')}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89572.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89572.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89572.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java:Map

文章目錄Map常用方法Map遍歷的三種方法先獲取Map集合的全部鍵,再通過遍歷來找值Entry對象forEach結合lambda表達式Map 案例分析需求我的代碼(不好)老師的代碼(好)好在哪里另外集合分為Collection和MapMap常用方法 代碼…

fastjson2 下劃線字段轉駝峰對象

在對接第三方或查詢數據庫時,返回的字段是下劃線分隔的,而在業務中需要轉成java對象,java對象的字段是駝峰的,使用fastjson2時,有兩種方法可以實現: 比如數據格式是: {"item_id": &q…

【硬件】藍牙音頻協議

1. 無線音頻傳輸的工作原理 在無線傳輸的過程中,音源設備首先將MP3、FLAC等音頻文件還原為PCM格式。通過藍牙音頻編碼轉為藍牙無線傳輸的文件,發送到音頻設備段。將藍牙無線傳輸的文件再次還原為PCM格式,之后轉為模擬信號并放大,通…

【宇樹科技:未來1-3年,機器人可流水線打螺絲】

在第三屆中國國際供應鏈促進博覽會上,宇樹科技工作人員表示,未來1到3年內,機器人產品有望從單一工業化產品,發展至復合化工業場景,如機器人搬完箱子后,換個 “手” 就能在流水線上打螺絲。在3到10年內&…

Spring AI 1.0版本 + 千問大模型之 文本記憶對話

上篇文章,主要是簡單講解了一下文本對話的功能。由于模型不具備上下文記憶功能,只能一問一答。因此我們需要實現記憶對話功能,這樣大模型回答信息才能夠更加準確。 1、pom依賴 項目構建就不詳細說了,大家可以參考上篇 文本對話 文…

測試學習之——Pytest Day2

一、Pytest配置框架Pytest的配置旨在改變其默認行為,以適應不同的測試需求和項目結構。理解其配置層級和常用參數,是高效使用Pytest的基礎。1. 配置的意義與層級配置的本質在于提供一種機制,允許用戶根據項目特點、團隊規范或特定測試場景&am…

Go-Redis × RediSearch 全流程實踐

1. 連接 Redis ctx : context.Background()rdb : redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,Protocol: 2, // 推薦 RESP2// UnstableResp3: true, // 若要體驗 RESP3 Raw* })2. 準備示例數據 u…

深入理解指針(指針篇2)

在指針篇1我們已經了解了整型指針,當然還有很多其他類型的指針,像字符指針、數組指針、函數指針等,他們都有他們的特別之處,讓我們接著學習。1. 指針類型介紹和應用1.1 字符指針變量字符指針變量類型為char*,一般這樣使…

Python+Selenium自動化爬取攜程動態加載游記

1. 引言 在旅游行業數據分析、輿情監測或競品研究中&#xff0c;獲取攜程等平臺的游記數據具有重要價值。然而&#xff0c;攜程的游記頁面通常采用動態加載&#xff08;Ajax、JavaScript渲染&#xff09;&#xff0c;傳統的**<font style"color:rgb(64, 64, 64);backg…

ESP8266服務器建立TCP連接失敗AT+CIPSTART=“TCP“,“192.168.124.1“,8080 ERROR CLOSED

1.檢查服務器端口8081是否開啟監聽2.檢查路由項是否被防火墻攔截方法 1&#xff1a;使用 netsh查看防火墻規則?netsh advfirewall firewall show rule nameall dirout | findstr "8081"如果無輸出&#xff0c;說明防火墻未針對該端口設置規則&#xff08;可能默認攔…

Linux 內存管理(2):了解內存回收機制

目錄一、透明大頁1.1 原理1.2 透明大頁的三大優勢1.3 透明大頁控制接口詳解1.4 使用場景與最佳實踐1.5 問題排查與監控1.6 與傳統大頁的對比二、Linux伙伴系統水位機制詳解2.1 三種核心水位詳解2.2 水位在伙伴系統中的實現2.3 水位觸發機制的實際行為2.4 水位關鍵操作接口2.5 水…

前端學習7:CSS過渡與動畫--補間動畫 (Transition) vs 關鍵幀動畫 (Animation)

一、補間動畫&#xff08;Tween Animation&#xff09;vs 關鍵幀動畫&#xff08;Keyframe Animation&#xff09;概念對比表&#xff1a;補間動畫 (Transition)關鍵幀動畫 (Animation)定義元素從初始狀態到結束狀態的過渡效果通過定義多個關鍵幀控制動畫的中間狀態觸發方式需要…

PyTorch 損失函數詳解:從理論到實踐

目錄 一、損失函數的基本概念 二、常用損失函數及實現 1. 均方誤差損失&#xff08;MSELoss&#xff09; 2. 平均絕對誤差損失&#xff08;L1Loss/MAELoss&#xff09; 3. 交叉熵損失&#xff08;CrossEntropyLoss&#xff09; 4. 二元交叉熵損失&#xff08;BCELoss&…

MinIO深度解析:從核心特性到Spring Boot實戰集成

在當今數據爆炸的時代&#xff0c;海量非結構化數據的存儲與管理成為企業級應用的關鍵挑戰。傳統文件系統在TB級數據面前捉襟見肘&#xff0c;而昂貴的云存儲服務又讓中小企業望而卻步。MinIO作為一款開源高性能對象存儲解決方案&#xff0c;正以其獨特的技術優勢成為開發者的首…

騰訊云服務上下載docker以及使用Rabbitmq的流程

執行以下命令&#xff0c;添加 Docker 軟件源并配置為騰訊云源。sudo yum-config-manager --add-repohttps://mirrors.cloud.tencent.com/docker-ce/linux/centos/docker-ce.repo sudo sed -i "s/download.docker.com/mirrors.tencentyun.com\/docker-ce/g" /etc/yu…

UE5 一些關于過場動畫sequencer,軌道track的一些Python操作

刪除多余的軌道 import unreal def execute():movie_scene_actors []sequence_assets []data 0.0# 獲取編輯器實用工具庫lib unreal.EditorUtilityLibrary()selected_assets lib.get_selected_assets()for asset in selected_assets:if asset.get_class() unreal.LevelS…

前端性能優化“核武器”:新一代圖片格式(AVIF/WebP)與自動化優化流程實戰

前端性能優化“核武器”&#xff1a;新一代圖片格式(AVIF/WebP)與自動化優化流程實戰 當你的頁面加載時間超過3秒時&#xff0c;用戶的跳出率會飆升到40%以上。而在所有的前端性能優化手段中&#xff0c;圖片優化無疑是投入產出比最高的一環。一張未經優化的巨大圖片&#xff0…

單元測試學習+AI輔助單測

標題單元測試衡量指標具體測試1、Resource2、MockBean3、Test4、Test模板5、單測示例H2數據庫JSON1、使用方式AI輔助單測使用方法單元測試 單元測試一般指程序員在寫好代碼后&#xff0c;提交測試前&#xff0c;需要驗證自己的代碼是否可以正常工作&#xff0c;同時將自己的代…

Spring Cloud Gateway與Envoy Sidecar在微服務請求路由中的架構設計分享

Spring Cloud Gateway與Envoy Sidecar在微服務請求路由中的架構設計分享 在現代微服務架構中&#xff0c;請求路由層承擔著流量分發、安全鑒權、流量控制等多重職責。傳統的單一網關方案往往面臨可擴展性和可維護性挑戰。本文將從真實生產環境出發&#xff0c;分享如何結合Spri…

GitHub Pages+Jekyll 靜態網站搭建(二)

GitHub PagesJekyll 靜態網站搭建&#xff08;二&#xff09;GitHub PagesJekyll 靜態網站搭建&#xff08;二內容簡介搭建模板網站部署工作流程GitHub PagesJekyll 靜態網站搭建&#xff08;二 內容簡介 &#x1f6a9; Tech Contents 該文主要涉及Jekyll主題的下載與使用。Gi…