1# 外设扩展驱动客户端开发指导
2
3## 场景介绍
4
5扩展外设主要是指通过物理接口连入主设备的配件设备,如手写板、打印机和扫描仪等。应用通过扩展外设管理能力可以查询绑定扩展外设,从而使用扩展外设驱动提供的定制能力来使用扩展外设,如打印机的配套软件。
6
7扩展外设管理能力支持所有可移植OpenHarmony系统的设备使用。
8
9## 环境搭建
10
11### 开发工具及配置
12
13DevEco Studio是驱动开发工具,进行驱动开发必备条件之一,我们可以使用该工具进行开发、调试、打包等操作。
14
15请[下载安装](https://developer.huawei.com/consumer/cn/download/)该工具,并参考[DevEco Studio使用指南](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-tools-overview-V13)中的[创建工程及运行](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-create-new-project-V13)进行基本的操作验证,保证DevEco Studio可正常运行。
16
17### SDK版本配置
18
19扩展外设管理提供的ArkTs接口,所需SDK版本为API10及以上版本才可使用。
20
21### HDC配置
22
23HDC(HarmonyOS Device Connector)是为开发人员提供的用于调试的命令行工具,通过该工具可以在Windows/Linux/Mac系统上与真实设备或者模拟器进行交互,详细参考[HDC配置](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/hdc-V5)24
25**注意:** “配置环境变量hdc_server_port”和“全局环境变量”为必须操作。
26
27### 开发设备
28
29* 当前开发调试及验证,以RK3568作为开发设备进行说明。关于RK3568的编译、烧录操作等方法,可参考[快速入门](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-pkg-3568-burn.md)30* 开发客户端和驱动时,需要一个外接USB设备进行调试,**当前仅支持USB总线的外接设备**。
31* 需要知道外接USB设备的ProductId和VendorId,用于定义驱动以及IPC通信。
32
33## 接口说明
34
35扩展外设管理基本能力如下,更多详情请查阅[API参考文档](../../reference/apis-driverdevelopment-kit/js-apis-driver-deviceManager.md)。
36
37**表1** 扩展外设管理基本能力接口
38
39| 接口名                                                                                                                                                       | 描述                                                                                    |
40| -----------------------------------------------------------------------------------------------------------------------------------------------------------  | --------------------------------------------------------------------------------------- |
41| queryDevices(busType?: number): Array<Readonly<Device>>                                                                                          | 查询扩展外设列表。                                                                       |
42| bindDevice(deviceId: number, onDisconnect: AsyncCallback<number>, callback: AsyncCallback<{deviceId: number; remote: rpc.IRemoteObject;}>): void | 绑定设备,绑定成功后返回设备驱动的IRemoteObject通信对象,通过该对象与设备驱动进行交互。 |
43| bindDevice(deviceId: number, onDisconnect: AsyncCallback<number>): Promise<{deviceId: number; remote: rpc.IRemoteObject;}>                       | 绑定设备的Promise形式。                                                                 |
44| bindDeviceDriver(deviceId: number, onDisconnect: AsyncCallback<number>, callback: AsyncCallback>RemoteDeviceDriver>): void;                                  | 绑定设备,API11开始支持。                                                                 |
45| bindDeviceDriver(deviceId: number, onDisconnect: AsyncCallback<number>): Promise<RemoteDeviceDriver>;                                                        | 绑定设备的Promise形式,API11开始支持。
46| unbindDevice(deviceId: number, callback: AsyncCallback<number>): void                                                                                  | 解绑设备。                                                                              |
47| unbindDevice(deviceId: number): Promise<number>                                                                                                        | 解绑设备的Promise形式。                                                                              |
48
49<!--Del-->
50扩展外设管理系统接口如下,具体请查阅[API参考文档](../../reference/apis-driverdevelopment-kit/js-apis-driver-deviceManager-sys.md)。
51
52**表2** 扩展外设管理系统接口
53
54| 接口名                                                                          | 描述              |
55|------------------------------------------------------------------------------|-----------------|
56| queryDeviceInfo(deviceId?: number): Array&lt;Readonly&lt;DeviceInfo&gt;&gt;  | 查询扩展外设详细信息列表。   |
57| queryDriverInfo(driverUid?: string): Array&lt;Readonly&lt;DriverInfo&gt;&gt; | 查询扩展外设驱动详细信息列表。 |
58<!--DelEnd-->
59
60## 开发步骤
61
62应用可通过查询绑定扩展外设,从而使用扩展外设的定制驱动能力。
63
64开发示例如下(仅供参考):为开发者提供的示例代码为同时开发客户端和服务端的Demo,并实现IPC通信。
65
661. 创建新工程,请参考[创建一个新的工程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-create-new-project-V13),创建一个OpenHarmony工程。
67
68    **注意:**
69
70    > 开发驱动客户端,请选择Empty Ability模板。
71    >
72    > 开发驱动服务端,请选择Native C++模板。
73    >
74    >同时开发驱动客户端和服务端,请选择Native C++模板。
75
76
772. 在文件中导入相关Kit,并声明想要绑定的USB设备的productId、vendorId以及与驱动通信的Code。
78
79    **说明:**
80
81    > 以下示例代码均写在entry/src/main/ets/pages/Index.ets文件中。
82
83    ```ts
84    import { hilog } from '@kit.PerformanceAnalysisKit';
85    import { deviceManager } from '@kit.DriverDevelopmentKit';
86    import { BusinessError } from '@kit.BasicServicesKit';
87    import { rpc } from '@kit.IPCKit';
88
89    const REQUEST_CODE: number = 99; // 自定义通信Code,此处仅供参考
90    const productId: number = 4258;  // 请声明连接的USB设备的productId
91    const vendorId: number = 4817;   // 请声明连接的USB设备的vendorId
92    ```
93
943. 定义message变量和远程对象变量,后续与驱动通信使用。
95
96    **说明:**
97
98    > 第3步开始,以下接口均在struct Index{}中定义。
99
100    ```ts
101    @State message: string = 'Hello';
102    private remote: rpc.IRemoteObject | null = null;
103    ```
104
1054. 定义查询设备接口,通过queryDevices获取目标设备ID。
106
107    ```ts
108    private async queryTargetDeviceId(): Promise<number> {
109    try {
110      const devices: Array<deviceManager.Device> = deviceManager.queryDevices(deviceManager.BusType.USB);
111      const index = devices.findIndex((item: deviceManager.Device) => {
112        let usbDevice = item as deviceManager.USBDevice;
113        // 如果不知道设备productId和vendorId,可以通过该日志查看连接的usb设备的相关信息
114        hilog.info(0, 'testTag', `usbDevice.productId = ${usbDevice.productId}, usbDevice.vendorId = ${usbDevice.vendorId}`);
115        return usbDevice.productId === productId && usbDevice.vendorId === vendorId;
116      });
117      if (index < 0) {
118        hilog.error(0, 'testTag', 'can not find device');
119        return -1;
120      }
121      return devices[index].deviceId;
122    } catch (error) {
123      hilog.error(0, 'testTag', `queryDevice failed, err: ${JSON.stringify(error)}`);
124    }
125    return -1;
126    }
127    ```
128
1295. 定义获取对应驱动远程对象的接口,通过bindDeviceDriver获取远程对象。
130
131    ```ts
132    private async getDriverRemote(deviceId: number): Promise<rpc.IRemoteObject | null> {
133    try {
134      let remoteDeviceDriver: deviceManager.RemoteDeviceDriver = await deviceManager.bindDeviceDriver(deviceId,
135        (err: BusinessError, id: number) => {
136        hilog.info(0, 'testTag', `device[${id}] id disconnect, err: ${JSON.stringify(err)}}`);
137      });
138      return remoteDeviceDriver.remote;
139    } catch (error) {
140      hilog.error(0, 'testTag', `bindDeviceDriver failed, err: ${JSON.stringify(error)}`);
141    }
142      return null;
143    }
144    ```
145
1466. 定义与远程对象通信接口,通过sendMessageRequest与远程对象进行IPC通信。
147
148    ```ts
149    private async communicateWithRemote(): Promise<void> {
150      const deviceId: number = await this.queryTargetDeviceId();
151      if (deviceId < 0) {
152        hilog.error(0, 'testTag', 'can not find target device');
153        return;
154      }
155      this.remote = await this.getDriverRemote(deviceId);
156      if (this.remote === null) {
157        hilog.error(0, 'testTag', `getDriverRemote failed`);
158        return;
159      }
160
161      let option = new rpc.MessageOption();
162      let data = new rpc.MessageSequence();
163      let reply = new rpc.MessageSequence();
164
165      // 向驱动发送信息"Hello"
166      data.writeString(this.message);
167
168      try {
169        await this.remote.sendMessageRequest(REQUEST_CODE, data, reply, option);
170        // 获取驱动返回信息"Hello world"
171        this.message = reply.readString();
172        hilog.info(0, 'testTag', `sendMessageRequest, message: ${this.message}}`);
173      } catch (error) {
174        hilog.error(0, 'testTag', `sendMessageRequest failed, err: ${JSON.stringify(error)}`);
175      }
176    }
177    ```
178
1797. 渲染UI界面,更多UI界面开发请参考[UI开发](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-ui-development-V5)180
181    ```ts
182    build() {
183      Row() {
184        Column() {
185          Text(this.message) // 显示"Hello"
186            .fontSize(60)
187            .fontWeight(FontWeight.Bold)
188            .onClick(() => { // 点击"Hello",与远程对象通信,显示"Hello World"
189              this.communicateWithRemote();
190            })
191        }
192        .width('100%')
193      }
194      .height('100%')
195    }
196    ```
197
1988. 接下来请参考[外设扩展驱动开发指导](driverextensionability.md),进行对应驱动的示例代码开发。
199
200<!--Del-->
201系统应用可通过查询外设详细信息和驱动详细信息,从而管理外设和驱动。开发示例如下:
202
2031. 导入相关Kit。
204
205    ```ts
206     import { deviceManager } from '@kit.DriverDevelopmentKit';
207     import { BusinessError } from '@kit.BasicServicesKit';
208    ```
209
2102. 查询扩展外设详细信息列表。
211
212    ```ts
213    try {
214       // 12345678为示例deviceId,应用开发时可通过queryDevices查询到相应设备的deviceId作为入参
215       let deviceInfos : Array<deviceManager.DeviceInfo> = deviceManager.queryDeviceInfo(12345678);
216       for (let item of deviceInfos) {
217          console.info(`Device id is ${item.deviceId}`)
218       }
219     } catch (error) {
220       let err: BusinessError = error as BusinessError;
221       console.error(`Failed to query device info. Code is ${err.code}, message is ${err.message}`);
222     }
223    ```
224
2253. 查询扩展外设驱动详细信息列表。
226
227    ```ts
228    try {
229       // driver-12345为示例driverUid,应用开发时可通过queryDeviceInfo查询到相应设备匹配到的驱动的driverUid作为入参
230       let driverInfos : Array<deviceManager.DriverInfo> = deviceManager.queryDriverInfo("driver-12345");
231       for (let item of driverInfos) {
232          console.info(`driver name is ${item.driverName}`)
233       }
234    } catch (error) {
235       let err: BusinessError = error as BusinessError;
236       console.error(`Failed to query driver info. Code is ${err.code}, message is ${err.message}`);
237    }
238    ```
239<!--DelEnd-->
240
241## 应用签名
242
243**注意:** 先配置权限,再自动签名。
244
245应用需要配置签名文件才能在设备上运行,并且扩展外设管理客户端开发,需要配置扩展外设的权限:ohos.permission.ACCESS_EXTENSIONAL_DEVICE_DRIVER246
247自动签名方法: 请参考[自动签名](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-signing-V13#section18815157237)248
249权限配置方法: 请参考[使用ACL的签名配置指导](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-signing-V13#section157591551175916)250