如何进行蓝牙连接
场景说明
蓝牙技术是一种无线数据和语音通信开放的全球规范,它是基于低成本的近距离无线连接,为固定和移动设备建立通信环境的一种特殊的连接。本示例通过@ohos.bluetoothManager接口实现蓝牙设备发现、配对、取消配对功能。
效果呈现
本示例最终效果如下:
发现设备 | 连接设备 | 断开连接 |
---|---|---|
点击领取→纯血鸿蒙Next全套最新学习资料
运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发。
- IDE:DevEco Studio 3.1.1 Release
- SDK:Ohos_sdk_full 4.0.8.5(API Version 10 Beta1)
实现思路
本文涉及到蓝牙的设备发现、配对、取消配对三个功能特性,实现思路如下:
- 启动和关闭蓝牙:在Index页面中通过Toggle组件的onChange函数控制蓝牙的开关,开关打开的情况下执行initBluetooth函数,关闭的情况下执行bluetooth.disableBluetooth()方法来断开蓝牙;
- 验证蓝牙是否处于连接状态:蓝牙打开的时候通过bluetooth.on('stateChange')方法监听蓝牙连接状态改变事件,如确认已打开,执行foundDevices()函数来查找设备接口,确认已关闭则执行bluetooth.stopBluetoothDiscovery()方法停止查询接口。
- 发现设备:在foundDevices()函数中通过bluetooth.on('bluetoothDeviceFind')方法监听设备发现事件,通过bluetooth.getPairedDevices()方法更新已配对蓝牙地址,然后通过bluetooth.startBluetoothDiscovery()方法开启蓝牙扫描发现远端设备,并且通过bluetooth.setBluetoothScanMode()方法来被远端设备发现。
- 蓝牙配对:通过bluetooth.on('pinRequired')方法监听远端蓝牙设备的配对请求事件,点击配对执行bluetooth.setDevicePairingConfirmation(this.data.deviceId, true)方法,点击取消执行bluetooth.setDevicePairingConfirmation(this.data.deviceId, false)方法。
- 取消配对:使用bluetooth.cancelPairedDevice()断开指定的远端设备连接。
开发步骤
-
申请蓝牙权限。 使用蓝牙需要先申请对应的权限,在module.json5文件中添加以下配置:
"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.APPROXIMATELY_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" } } ]
-
构建UI框架,整体的UI框架分为TitleBar(页面名称),PinDialog(配对蓝牙弹框),index(主页面)三个部分。
//Common/TitleBar.ets @Component export struct TitleBar { private handlerClickButton: () => void build() { Row() { Image($r('app.media.ic_back')) .width(40) .height(30) .onClick(() => { this.handlerClickButton() }) Text($r('app.string.bluetooth')) .fontSize(30) .width(150) .height(50) .margin({ left: 15 }) .fontColor('#ffa2a3a4') } .width('100%') .height(60) .padding({ left: 20, top: 10 }) .backgroundColor('#ff2d30cb') .constraintSize({ minHeight: 50 }) } } //Common/PinDalog.ets ... aboutToAppear() { this.titleText = `"${this.data.deviceId}"要与您配对。请确认此配对码已在"${this.data.deviceId}"上直接显示,且不是手动输入的。` this.pinCode = JSON.stringify(this.data.pinCode) } build() { //配对弹框描述文字 Column({ space: 10 }) { Text($r('app.string.match_request')) .fontSize(30) .alignSelf(ItemAlign.Start) Text(this.titleText) .alignSelf(ItemAlign.Start) .margin({ top: 20 }) .fontSize(21) Text(this.pinCode) .fontSize(40) .fontWeight(FontWeight.Bold) .margin({ top: 20 }) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { Checkbox({ name: 'checkbox' }) .select(false) .selectedColor('#ff3d6fb8') .key('checkBox') Text($r('app.string.grant_permission')) .fontSize(15) .margin({ left: 3, top: 6 }) } .alignSelf(ItemAlign.Start) .width('95%') .margin({ top: 5 }) Row() { //配对选择UI,取消or配对 this.choiceText($r('app.string.cancel'), () => { bluetooth.setDevicePairingConfirmation(this.data.deviceId, false) logger.info(TAG, `setDevicePairingConfirmation = ${bluetooth.setDevicePairingConfirmation(this.data.deviceId, false)}`) this.controller.close() }) Divider() .vertical(true) .height(32) this.choiceText($r('app.string.match'), () => { bluetooth.setDevicePairingConfirmation(this.data.deviceId, true) logger.info(TAG, `setDevicePairingConfirmation = ${bluetooth.setDevicePairingConfirmation(this.data.deviceId, true)}`) this.controller.close() }) } .margin({ top: 20 }) } .width('100%') .padding(15) } ... //pages/index.ets @Entry @Component struct Index { build() { Column() { TitleBar({ handlerClickButton: this.handlerClickButton }) Scroll() { Column() { Row() { //蓝牙开关 Column() { Text($r('app.string.bluetooth')) .fontSize(30) .margin({ top: 20 }) .alignSelf(ItemAlign.Start) if (true === this.isOn) { Text($r('app.string.discovery')) .fontSize(20) .alignSelf(ItemAlign.Start) } } Blank() Column() { Toggle({ type: ToggleType.Switch, isOn: this.isOn }) .selectedColor('#ff2982ea') .onChange((isOn: boolean) => { if (isOn) { this.isOn = true this.initBluetooth() } else { this.isOn = false bluetooth.disableBluetooth() this.deviceList = [] this.discoveryList = [] } }) } .id('toggleBtn') } .width('90%') if (this.isOn) { Divider() .vertical(false) .strokeWidth(10) .color('#ffece7e7') .lineCap(LineCapStyle.Butt) .margin('1%') //已配对的设备 Text($r('app.string.paired_device')) .fontSize(25) .fontColor('#ff565555') .margin({ left: '5%' }) .alignSelf(ItemAlign.Start) ForEach(this.deviceList, (item, index) => { Row() { Text(item) .fontSize(20) } .alignSelf(ItemAlign.Start) .width('100%') .height(50) .margin({ left: '5%', top: '1%' }) .id(`pairedDevice${index}`) .onClick(() => { AlertDialog.show({ //取消配对 title: $r('app.string.disconnect'), message: '此操作将会断开您与以下设备的连接:' + item, primaryButton: { value: $r('app.string.cancel'), action: () => { } }, //确认取消 secondaryButton: { value: $r('app.string.confirm'), action: () => { try { bluetooth.cancelPairedDevice(item); this.deviceList = bluetooth.getPairedDevices() this.discoveryList = [] bluetooth.startBluetoothDiscovery() } catch (err) { console.error("errCode:" + err.code + ",errMessage:" + err.message); } } } }) }) }) Divider() .vertical(false) .strokeWidth(10) .color('#ffece7e7') .lineCap(LineCapStyle.Butt) .margin('1%') Text($r('app.string.available_device')) .fontSize(25) .fontColor('#ff565555') .margin({ left: '5%', bottom: '2%' }) .alignSelf(ItemAlign.Start) //可用设备列表 ForEach(this.discoveryList, (item) => { Row() { Text(item) .fontSize(20) } .alignSelf(ItemAlign.Start) .width('100%') .height(50) .margin({ left: '5%', top: '1%' }) //进行配对操作点击 .onClick(() => { logger.info(TAG, `start bluetooth.pairDevice,item = ${item}`) let pairStatus = bluetooth.pairDevice(item) logger.info(TAG, `pairStatus = ${pairStatus}`) }) Divider() .vertical(false) .color('#ffece7e7') .lineCap(LineCapStyle.Butt) .margin('1%') }) } } } .constraintSize({ maxHeight: '85%' }) } } }
-
蓝牙开关打开关闭操作,需要打开蓝牙开关才能进行后续操作:
initBluetooth() { bluetooth.on('stateChange', (data) => { logger.info(TAG, `enter on stateChange`) //判断蓝牙开关状态 if (data === bluetooth.BluetoothState.STATE_ON) { logger.info(TAG, `enter BluetoothState.STATE_ON`) //蓝牙打开后的相关操作 this.foundDevices() } if (data === bluetooth.BluetoothState.STATE_OFF) { logger.info(TAG, `enter BluetoothState.STATE_OFF`) bluetooth.off('bluetoothDeviceFind', (data) => { logger.info(TAG, `offBluetoothDeviceFindData = ${JSON.stringify(data)}`) }) //关闭 bluetooth.stopBluetoothDiscovery() this.discoveryList = [] } logger.info(TAG, `BluetoothState = ${JSON.stringify(data)}`) }) //开启蓝牙 bluetooth.enableBluetooth() }
-
设置蓝牙扫描模式并开启扫描去发现设备,并订阅蓝牙设备发现上报时间获取设备列表
foundDevices() { //订阅蓝牙设备发现上报事件 bluetooth.on('bluetoothDeviceFind', (data) => { logger.info(TAG, `enter on bluetoothDeviceFind`) if (data !== null && data.length > 0) { if (this.discoveryList.indexOf(data[0]) === -1 && this.deviceList.indexOf(data[0]) === -1) { this.discoveryList.push(data[0]) } logger.info(TAG, `discoveryList = ${JSON.stringify(this.discoveryList)}`) } let list = bluetooth.getPairedDevices() if (list !== null && list.length > 0) { this.deviceList = list logger.info(TAG, `deviceList = ${JSON.stringify(this.deviceList)}`) } }) //开启蓝牙扫描,可以发现远端设备 bluetooth.startBluetoothDiscovery() //设置蓝牙扫描模式,可以被远端设备发现 bluetooth.setBluetoothScanMode(bluetooth.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, TIME) }
-
设置蓝牙扫描模式并开启扫描去发现设备,并订阅蓝牙设备发现上报时间获取设备列表
//配对确定和取消代码在PinDialog.ets文件中 //setDevicePairingConfirmation(device: string, accept: boolean): void //device string 表示远端设备地址,例如:"XX:XX:XX:XX:XX:XX //accept boolean 接受配对请求设置为true,否则设置为false //订阅蓝牙配对状态改变事件,根据蓝牙状态更新设备列表 bluetooth.on('bondStateChange', (data) => { logger.info(TAG, `enter bondStateChange`) logger.info(TAG, `data = ${JSON.stringify(data)}`) if (data.state === bluetooth.BondState.BOND_STATE_BONDED) { logger.info(TAG, `BOND_STATE_BONDED`) let index = this.discoveryList.indexOf(data.deviceId) this.discoveryList.splice(index, 1) this.deviceList = bluetooth.getPairedDevices() } if (data.state === bluetooth.BondState.BOND_STATE_INVALID) { logger.info(TAG, `BOND_STATE_INVALID`) this.deviceList = bluetooth.getPairedDevices() } logger.info(TAG, `bondStateChange,data = ${JSON.stringify(data)}`) })
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习
点击领取→纯血鸿蒙Next全套最新学习资料(安全链接,放心点击)
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
一、鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
二、HarmonyOS Next 最新全套视频教程
三、《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
- ArkTS语言
- 安装DevEco Studio
- 运用你的第一个ArkTS应用
- ArkUI声明式UI开发
- .……
《鸿蒙开发进阶》
- Stage模型入门
- 网络管理
- 数据管理
- 电话服务
- 分布式应用开发
- 通知与窗口管理
- 多媒体技术
- 安全技能
- 任务管理
- WebGL
- 国际化开发
- 应用测试
- DFX面向未来设计
- 鸿蒙系统移植和裁剪定制
- ……
《鸿蒙进阶实战》
- ArkTS实践
- UIAbility应用
- 网络案例
- ……
四、大厂面试必问面试题
五、鸿蒙南向开发技术
六、鸿蒙APP开发必备
七、鸿蒙生态应用开发白皮书V2.0PDF
完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。