• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![pair request dialog](figures/pair-request-dialog.png)
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```