当前位置: 首页 > news >正文

鸿蒙蓝牙通信

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.lryc.cn/news/593694.html

相关文章:

  • 【Java源码阅读系列56】深度解读Java Constructor 类源码
  • GitLab 社区版 10.8.4 安装、汉化与使用教程
  • AI编程工具对比:Cursor、GitHub Copilot与Claude Code
  • 【SVM smote】MAP - Charting Student Math Misunderstandings
  • sqli-labs靶场通关笔记:第32-33关 宽字节注入
  • Kotlin方差
  • 1 渗透基础
  • ros2高级篇之高可用启动文件及配置编写
  • Spring AI 1.0版本 + 千问大模型之文本对话
  • node.js学习笔记1
  • 【数据类型与变量】
  • MySQL——约束类型
  • Springboot项目的搭建方式5种
  • 使用DataGrip连接安装在Linux上的Redis
  • Python+大模型 day02
  • 辛普森悖论
  • 使用看门狗实现复位
  • 1.初始化
  • Web开发 03
  • 双目摄像头品牌
  • 板子 5.29--7.19
  • 【科研绘图系列】R语言绘制显著性标记的热图
  • 【黄山派-SF32LB52】—硬件原理图学习笔记
  • 商业秘密视域下计算机软件的多重保护困境
  • 计算机网络:(十)虚拟专用网 VPN 和网络地址转换 NAT
  • Java多线程基础详解:从实现到线程安全
  • 6. 装饰器模式
  • ROS2 视频采集节点实现
  • Redis常见线上问题
  • 基于LSTM的时间序列到时间序列的回归模拟