1# 配对与连接设备 2 3<!--Kit: Connectivity Kit--> 4<!--Subsystem: Communication--> 5<!--Owner: @enjoy_sunshine--> 6<!--Designer: @chengguohong; @tangjia15--> 7<!--Tester: @wangfeng517--> 8<!--Adviser: @zhang_yixin13--> 9 10## 简介 11本指南主要提供了主动配对设备和连接设备可用profile能力的开发指导。 12 13## 开发步骤 14 15### 申请蓝牙权限 16需要申请权限ohos.permission.ACCESS_BLUETOOTH。如何配置和申请权限,具体操作请参考[声明权限](../../security/AccessToken/declare-permissions.md)和[向用户申请授权](../../security/AccessToken/request-user-authorization.md)。 17 18### 导入所需API模块 19导入connection、a2dp、 hfp、 hid、baseProfile、constant和错误码模块。 20```ts 21import { connection, a2dp, hfp, hid, baseProfile, constant } from '@kit.ConnectivityKit'; 22import { BusinessError } from '@kit.BasicServicesKit'; 23``` 24 25### 订阅配对状态变化事件 26通过订阅配对状态变化事件,可以获取实时的配对状态。在整个配对过程中,涉及多种状态的跃迁,其中[BOND_STATE_BONDED](../../reference/apis-connectivity-kit/js-apis-bluetooth-connection.md#bondstate)表示已配对。 27 28应用主动发起配对其他设备,或者其他设备主动配对本机设备,都可以通过此事件获取配对情况。 29```ts 30// 定义配对状态变化函数回调 31function onReceiveEvent(data: connection.BondStateParam) { 32 console.info('pair result: '+ JSON.stringify(data)); 33} 34 35try { 36 // 发起订阅 37 connection.on('bondStateChange', onReceiveEvent); 38} catch (err) { 39 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 40} 41``` 42 43### 发起配对 44若目标设备的配对状态是[BOND_STATE_INVALID](../../reference/apis-connectivity-kit/js-apis-bluetooth-connection.md#bondstate),则可以主动配对目标设备。 45- 目标设备可以通过发现设备流程获取,详情请参考:[传统蓝牙查找设备](br-discovery-development-guide.md)或者[低功耗蓝牙查找设备](ble-development-guide.md)。 46 47配对过程中,系统会弹出对话框。不同配对类型,对话框样式可能不一样,其中“确认配对密钥(Confirm Passkey)”模式如下图1。若用户同意授权,才能配对成功。 48 49 50 51**图1** 蓝牙配对请求对话框 52```ts 53// 设备地址可以通过查找设备流程获取 54let device = 'XX:XX:XX:XX:XX:XX'; 55 56try { 57 // 发起配对 58 connection.pairDevice(device).then(() => { 59 console.info('pairDevice'); 60 }, (error: BusinessError) => { 61 console.error('pairDevice: errCode:' + error.code + ',errMessage' + error.message); 62 }); 63} catch (err) { 64 console.error('startPair: errCode:' + err.code + ',errMessage' + err.message); 65} 66``` 67 68### 连接已配对设备的profile 69若应用配对完目标设备后,可以调用[connectAllowedProfiles](../../reference/apis-connectivity-kit/js-apis-bluetooth-connection.md#connectionconnectallowedprofiles16),发起连接该设备支持的profile能力(只包括A2DP、HFP和HID)。若应用需要使用SPP连接,请参考[连接和传输数据](spp-development-guide.md)。 70 71- 蓝牙子系统会在配对过程中查询和保存目标设备支持的所有profile能力。 72- 配对完成后,应用可以主动查询目标设备的profile能力,需调用[getRemoteProfileUuids](../../reference/apis-connectivity-kit/js-apis-bluetooth-connection.md#connectiongetremoteprofileuuids12)。若存在应用需要的能力,则可以在配对完成后30s内,发起连接目标设备的profile。 73```ts 74// 设备地址是已配对的设备 75let device = 'XX:XX:XX:XX:XX:XX'; 76 77// 创建A2DP/HFP/HID实例 78let a2dpSrc = a2dp.createA2dpSrcProfile(); 79let hfpAg = hfp.createHfpAgProfile(); 80let hidHost = hid.createHidHostProfile(); 81 82// 定义A2DP连接状态变化回调函数 83function onA2dpConnectStateChange(data: baseProfile.StateChangeParam) { 84 console.info(`A2DP State: ${JSON.stringify(data)}`); 85} 86 87// 定义HFP连接状态变化回调函数 88function onHfpConnectStateChange(data: baseProfile.StateChangeParam) { 89 console.info(`HFP State: ${JSON.stringify(data)}`); 90} 91 92// 定义HID连接状态变化回调函数 93function onHidConnectStateChange(data: baseProfile.StateChangeParam) { 94 console.info(`HID State: ${JSON.stringify(data)}`); 95} 96 97try { 98 // 建议判断目标设备的profile能力是否存在A2DP/HFP/HID 99 // 订阅A2DP/HFP/HID连接状态变化事件 100 a2dpSrc.on('connectionStateChange', onA2dpConnectStateChange); 101 hfpAg.on('connectionStateChange', onHfpConnectStateChange); 102 hidHost.on('connectionStateChange', onHidConnectStateChange); 103 104 // 发起连接profile 105 connection.connectAllowedProfiles(device).then(() => { 106 console.info('connectAllowedProfiles'); 107 }, (error: BusinessError) => { 108 console.error('errCode:' + error.code + ',errMessage' + error.message); 109 }); 110} catch (err) { 111 console.error('errCode:' + err.code + ',errMessage' + err.message); 112} 113``` 114 115## 完整示例 116```ts 117import { connection, a2dp, hfp, hid, baseProfile, constant } from '@kit.ConnectivityKit'; 118import { BusinessError } from '@kit.BasicServicesKit'; 119 120export class PairDeviceManager { 121 device: string = ''; 122 pairState: connection.BondState = connection.BondState.BOND_STATE_INVALID; 123 a2dpSrc = a2dp.createA2dpSrcProfile(); 124 hfpAg = hfp.createHfpAgProfile(); 125 hidHost = hid.createHidHostProfile(); 126 127 // 定义配对状态变化回调函数 128 onBondStateEvent = (data: connection.BondStateParam) => { 129 console.info('pair result: '+ JSON.stringify(data)); 130 if (data && data.deviceId == this.device) { 131 this.pairState = data.state; // 保存目标设备的配对状态 132 } 133 }; 134 135 // 发起配对,设备地址可以通过查找设备流程获取 136 public startPair(device: string) { 137 this.device = device; 138 try { 139 // 发起订阅配对状态变化事件 140 connection.on('bondStateChange', this.onBondStateEvent); 141 } catch (err) { 142 console.error('bondStateChange errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 143 } 144 145 try { 146 // 发起配对 147 connection.pairDevice(device).then(() => { 148 console.info('pairDevice'); 149 }, (error: BusinessError) => { 150 console.error('pairDevice: errCode:' + error.code + ',errMessage' + error.message); 151 }); 152 } catch (err) { 153 console.error('startPair: errCode:' + err.code + ',errMessage' + err.message); 154 } 155 } 156 157 // 定义A2DP连接状态变化回调函数 158 onA2dpConnectStateChange = (data: baseProfile.StateChangeParam) => { 159 console.info(`A2DP State: ${JSON.stringify(data)}`); 160 }; 161 162 // 定义HFP连接状态变化回调函数 163 onHfpConnectStateChange = (data: baseProfile.StateChangeParam) => { 164 console.info(`HFP State: ${JSON.stringify(data)}`); 165 }; 166 167 // 定义HID连接状态变化回调函数 168 onHidConnectStateChange = (data: baseProfile.StateChangeParam) => { 169 console.info(`HID State: ${JSON.stringify(data)}`); 170 }; 171 172 // 发起连接 173 public async connect(device: string) { 174 try { 175 let uuids = await connection.getRemoteProfileUuids(device); 176 console.info('device: ' + device + ' remoteUuids: '+ JSON.stringify(uuids)); 177 let allowedProfiles = 0; 178 // 若存在应用需要的profile,则监听对应的profile连接状态 179 if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_A2DP_SINK.toLowerCase())) { 180 console.info('device supports a2dp'); 181 allowedProfiles++; 182 this.a2dpSrc.on('connectionStateChange', this.onA2dpConnectStateChange); 183 } 184 if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HFP_HF.toLowerCase())) { 185 console.info('device supports hfp'); 186 allowedProfiles++; 187 this.hfpAg.on('connectionStateChange', this.onHfpConnectStateChange); 188 } 189 if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HID.toLowerCase()) || 190 uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HOGP.toLowerCase())) { 191 console.info('device supports hid'); 192 allowedProfiles++; 193 this.hidHost.on('connectionStateChange', this.onHidConnectStateChange); 194 } 195 if (allowedProfiles > 0) { // 若存在可用的profile,则发起连接 196 connection.connectAllowedProfiles(device).then(() => { 197 console.info('connectAllowedProfiles'); 198 }, (error: BusinessError) => { 199 console.error('errCode:' + error.code + ',errMessage' + error.message); 200 }); 201 } 202 } catch (err) { 203 console.error('errCode:' + err.code + ',errMessage' + err.message); 204 } 205 } 206} 207 208let pairDeviceManager = new PairDeviceManager(); 209export default pairDeviceManager as PairDeviceManager; 210```