• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# OpenHarmony IDL工具规格及使用说明书(仅对系统应用开放)
2
3## IDL接口描述语言简介
4当客户端和服务器进行IPC通信时,需要定义双方都认可的接口,以保障双方可以成功通信,OpenHarmony IDL(OpenHarmony Interface Definition Language)则是一种定义此类接口的工具。OpenHarmony IDL先把需要传递的对象分解成操作系统能够理解的基本类型,并根据开发者的需要封装跨边界的对象。
5
6  **图1** IDL接口描述
7
8![IDL-interface-description](./figures/IDL-interface-description.png)
9
10 **OpenHarmony IDL接口描述语言主要用于:**
11
12- 声明系统服务对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。
13
14- 声明Ability对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。
15
16**图2** IPC/RPC通信模型
17
18![IPC-RPC-communication-model](./figures/IPC-RPC-communication-model.png)
19
20 **使用OpenHarmony IDL接口描述语言声明接口具有以下优点:**
21
22- OpenHarmony IDL中是以接口的形式定义服务,可以专注于定义而隐藏实现细节。
23
24- OpenHarmony IDL中定义的接口可以支持跨进程调用或跨设备调用。根据OpenHarmony IDL中的定义生成的信息或代码可以简化跨进程或跨设备调用接口的实现。
25
26## IDL接口描述语言构成
27
28### 数据类型
29
30#### 基础数据类型
31| IDL基本数据类型 | C++基本数据类型 | TS基本数据类型 |
32|   --------    |  --------     | --------     |
33|void           | void          | void         |
34|boolean        | bool          | boolean      |
35|byte           | int8_t        | number       |
36|short          | int16_t       | number       |
37|int            | int32_t       | number       |
38|long           | int64_t       | number       |
39|float          | float         | number       |
40|double         | double        | number       |
41|String         | std::string   | string       |
42
43IDL支持的基本数据类型及其映射到C++、TS上的数据类型的对应关系如上表所示。
44
45#### sequenceable数据类型
46sequenceable数据类型是指使用“sequenceable”关键字声明的数据,表明该数据类型可以被序列化进行跨进程或跨设备传递。sequenceable在C++与TS中声明方式存在一定差异。
47
48在C++中sequenceable数据类型的声明放在文件的头部,以“sequenceable includedir..namespace.typename”的形式声明。具体而言。声明可以有如下三个形式:
49
50```cpp
51sequenceable includedir..namespace.typename
52sequenceable includedir...typename
53sequenceable namespace.typename
54```
55
56其中,includedir表示该数据类型头文件所在目录,includedir中以“.”作为分隔符。namespace表示该数据类型所在命名空间,namespace中同样以“.”作为分隔符。typename表示数据类型,数据类型中不能包含非英文字符类型的其他符号。includedir与namespace之间通过“..”分割,如果类型声明的表达式中不包含“..”,除去最后一个typename之外的字符都会被解析为命名空间。例如:
57
58```cpp
59sequenceable a.b..C.D
60```
61
62 上述声明在生成的的C++头文件中将被解析为如下代码:
63
64```cpp
65#include  “a/b/d.h66using C::D;
67```
68
69TS声明放在文件的头部,以 “sequenceable namespace.typename;”的形式声明。具体而言,声明可以有如下形式(idl为对应namespace,MySequenceable为对应typename):
70
71```ts
72sequenceable idl.MySequenceable
73```
74
75其中,namespace是该类型所属的命名空间,typename是类型名。MySequenceable类型表示可以通过Parcel进行跨进程传递。sequenceable数据类型并不在OpenHarmony IDL文件中定义,而是定义在.ts文件中。因此,OpenHarmony IDL工具将根据声明在生成的.ts代码文件中加入如下语句:
76
77```ts
78import MySequenceable from "./my_sequenceable"
79```
80
81需要注意的是,IDL并不负责该类型的代码实现,仅仅按照指定的形式引入该头文件或import指定模块,并使用该类型,因此开发者需要自行保证引入目录、命名空间及类型的正确性。
82
83#### 接口类型
84 接口类型是指OpenHarmony IDL文件中定义的接口。对于当前IDL文件中定义的接口,可以直接使用它作为方法参数类型或返回值类型。而在其它OpenHarmony IDL文件中定义的接口,则需要在文件的头部进行前置声明。
85
86 C++中声明的形式与sequenceable类型相似,具体而言可以有如下形式:
87
88```cpp
89interface includedir..namespace.typename
90```
91
92 TS中声明的形式,具体而言可以有如下形式:
93
94```ts
95interface namespace.interfacename
96```
97
98其中,namespace是该接口所属的命名空间,interfacename是接口名。例如:“interface OHOS.IIdlTestObserver;”声明了在其他OpenHarmony IDL文件定义的IIdlTestObserver接口,该接口可以作为当前定义中方法的参数类型或返回值类型使用。OpenHarmony IDL工具将根据该声明在生成的TS代码文件中加入如下语句:
99
100```ts
101import IIdlTestObserver from "./i_idl_test_observer"
102```
103
104#### 数组类型
105数组类型使用“T[]”表示,其中T可以是基本数据类型、sequenceable数据类型、interface类型和数组类型。该类型在C++生成代码中将被生成为std::vector<T>类型。
106OpenHarmony IDL数组数据类型与TS数据类型、C++数据类型的对应关系如下表所示:
107
108|OpenHarmony IDL数据类型  | C++数据类型           | TS数据类型     |
109|   -------              |  --------            |  --------    |
110|T[]                     | std::vector<T> | T[]          |
111
112#### 容器类型
113IDL支持两种容器类型,即List和Map。其中List类型容器的用法为List&lt;T&gt;;Map容器的用法为Map<KT,VT>,其中T、KT、VT为基本数据类型、sequenceable类型、interface类型、数组类型或容器类型。
114
115List类型在C++代码中被映射为std::list,Map容器被映射为std::map。
116
117List类型在TS代码中不支持,Map容器被映射为Map。
118
119OpenHarmony IDL容器数据类型与Ts数据类型、C++数据类型的对应关系如下表所示:
120
121|OpenHarmony IDL数据类型  | C++数据类型       | TS数据类型     |
122|   --------             |  --------        |  -------     |
123|List&lt;T&gt;           | std::list        | 不支持        |
124|Map<KT,VT>              | std::map         | Map          |
125
126
127### IDL文件编写规范
128一个idl文件只能定义一个interface类型,且该interface名称必须和文件名相同。idl文件的接口定义使用BNF范式描述,其基本定义的形式如下:
129
130```
131[<*interface_attr_declaration*>]interface<*interface_name_with_namespace*>{<*method_declaration*>}
132```
133
134其中,<*interface_attr_declaration*>表示接口属性声明。当前仅支持“oneway”属性,表示该接口中的接口都是单向方法,即调用方法后不用等待该方法执行即可返回。这个属性为可选项,如果未声明该属性,则默认为同步调用方法。接口名需要包含完整的接口头文件目录及命名空间,且必须包含方法声明,不允许出现空接口。
135接口内的方法声明形式为:
136
137```
138[<*method_attr_declaration*>]<*result_type*><*method_declaration*>
139```
140
141其中,<*method_attr_declaration*>表示接口属性说明。当前仅支持“oneway”属性,表示该方法为单向方法,即调用方法后不用等待该方法执行即可返回。这个属性为可选项,如果未声明该属性,则默认为同步调用方法。<*result_type*>为返回值类型,<*method_declaration*>是方法名和各个参数声明。
142参数声明的形式为:
143
144```
145[<*formal_param_attr*>]<*type*><*identifier*>
146```
147
148其中<*formal_param_attr*>的值为“in”,“out”,“inout”,分别表示该参数是输入参数,输出参数或输入输出参数。需要注意的是,如果一个方法被声明为oneway,则该方法不允许有输出类型的参数(及输入输出类型)和返回值。
149
150## 开发步骤
151
152### IDL工具的获取
153首先,打开DevEco Studio—>Tools—>SDK Manager,查看OpenHarmony SDK的本地安装路径,此处以DevEco Studio 3.0.0.993版本为例,查看方式如下图所示。
154![SDKpath](./figures/SDKpath.png)
155![SDKpath](./figures/SDKpath2.png)
156
157进入对应路径后,查看toolchains->3.x.x.x(对应版本号命名文件夹)下是否存在idl工具的可执行文件。
158
159> **注意**:
160>
161> 请保证使用最新版的SDK,版本老旧可能导致部分语句报错。
162
163若不存在,可对应版本前往[docs仓版本目录](../../release-notes)下载SDK包,以[3.2Beta3版本](../../release-notes/OpenHarmony-v3.2-beta3.md)为例,可通过镜像站点获取。
164
165关于如何替换DevEco Studio的SDK包具体操作,参考[full-SDK替换指南](../faqs/full-sdk-compile-guide.md)中的替换方法。
166
167得到idl工具的可执行文件后,根据具体场景进行后续开发步骤。
168
169### TS开发步骤
170
171#### 创建.idl文件
172
173 开发者可以使用TS编程语言构建.idl文件。
174
175 例如,此处构建一个名为IIdlTestService.idl的文件,文件内具体内容如下:
176
177```cpp
178  interface OHOS.IIdlTestService {
179      int TestIntTransaction([in] int data);
180      void TestStringTransaction([in] String data);
181      void TestMapTransaction([in] Map<int, int> data);
182      int TestArrayTransaction([in] String[] data);
183  }
184```
185
186在idl的可执行文件所在文件夹下执行命令 `idl -gen-ts -d dir -c dir/IIdlTestService.idl`。
187
188-d后的dir为目标输出目录,以输出文件夹名为IIdlTestServiceTs为例,在idl可执行文件所在目录下执行`idl -gen-ts -d IIdlTestServiceTs -c IIdlTestServiceTs/IIdlTestService.idl`,将会在执行环境的dir目录(即IIdlTestServiceTs目录)中生成接口文件、Stub文件、Proxy文件。
189
190> **注意**:生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。
191
192以名为`IIdlTestService.idl`的.idl文件、目标输出文件夹为IIdlTestServiceTs为例,其目录结构应类似于:
193
194```
195├── IIdlTestServiceTs  # idl代码输出文件夹
196│   ├── i_idl_test_service.ts  # 生成文件
197│   ├── idl_test_service_proxy.ts  # 生成文件
198│   ├── idl_test_service_stub.ts  # 生成文件
199│   └── IIdlTestService.idl  # 构造的.idl文件
200└── idl.exe  # idl的可执行文件
201```
202
203#### 服务端公开接口
204
205OpenHarmony IDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法。
206
207```ts
208import {testIntTransactionCallback} from "./i_idl_test_service";
209import {testStringTransactionCallback} from "./i_idl_test_service";
210import {testMapTransactionCallback} from "./i_idl_test_service";
211import {testArrayTransactionCallback} from "./i_idl_test_service";
212import IIdlTestService from "./i_idl_test_service";
213import rpc from "@ohos.rpc";
214
215export default class IdlTestServiceStub extends rpc.RemoteObject implements IIdlTestService {
216    constructor(des: string) {
217        super(des);
218    }
219
220    async onRemoteMessageRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence,
221        option: rpc.MessageOption): Promise<boolean> {
222        console.log("onRemoteMessageRequest called, code = " + code);
223        if (code == IdlTestServiceStub.COMMAND_TEST_INT_TRANSACTION) {
224            let _data = data.readInt();
225            this.testIntTransaction(_data, (errCode: number, returnValue: number) => {
226                reply.writeInt(errCode);
227                if (errCode == 0) {
228                    reply.writeInt(returnValue);
229                }
230            });
231            return true;
232        } else if (code == IdlTestServiceStub.COMMAND_TEST_STRING_TRANSACTION) {
233            let _data = data.readString();
234            this.testStringTransaction(_data, (errCode: number) => {
235                reply.writeInt(errCode);
236            });
237            return true;
238        } else if (code == IdlTestServiceStub.COMMAND_TEST_MAP_TRANSACTION) {
239            let _data: Map<number, number> = new Map();
240            let _dataSize = data.readInt();
241            for (let i = 0; i < _dataSize; ++i) {
242                let key = data.readInt();
243                let value = data.readInt();
244                _data.set(key, value);
245            }
246            this.testMapTransaction(_data, (errCode: number) => {
247                reply.writeInt(errCode);
248            });
249            return true;
250        } else if (code == IdlTestServiceStub.COMMAND_TEST_ARRAY_TRANSACTION) {
251            let _data = data.readStringArray();
252            this.testArrayTransaction(_data, (errCode: number, returnValue: number) => {
253                reply.writeInt(errCode);
254                if (errCode == 0) {
255                    reply.writeInt(returnValue);
256                }
257            });
258            return true;
259        } else {
260            console.log("invalid request code" + code);
261        }
262        return false;
263    }
264
265    testIntTransaction(data: number, callback: testIntTransactionCallback): void{}
266    testStringTransaction(data: string, callback: testStringTransactionCallback): void{}
267    testMapTransaction(data: Map<number, number>, callback: testMapTransactionCallback): void{}
268    testArrayTransaction(data: string[], callback: testArrayTransactionCallback): void{}
269
270    static readonly COMMAND_TEST_INT_TRANSACTION = 1;
271    static readonly COMMAND_TEST_STRING_TRANSACTION = 2;
272    static readonly COMMAND_TEST_MAP_TRANSACTION = 3;
273    static readonly COMMAND_TEST_ARRAY_TRANSACTION = 4;
274}
275```
276
277开发者需要继承.idl文件中定义的接口类并实现其中的方法。在本示例中,我们继承了IdlTestServiceStub接口类并实现了其中的testIntTransaction、testStringTransaction、testMapTransaction和testArrayTransaction方法。具体的示例代码如下:
278
279```ts
280import {testIntTransactionCallback} from "./i_idl_test_service"
281import {testStringTransactionCallback} from "./i_idl_test_service"
282import {testMapTransactionCallback} from "./i_idl_test_service";
283import {testArrayTransactionCallback} from "./i_idl_test_service";
284import IdlTestServiceStub from "./idl_test_service_stub"
285
286
287class IdlTestImp extends IdlTestServiceStub {
288
289    testIntTransaction(data: number, callback: testIntTransactionCallback): void
290    {
291        callback(0, data + 1);
292    }
293    testStringTransaction(data: string, callback: testStringTransactionCallback): void
294    {
295        callback(0);
296    }
297    testMapTransaction(data: Map<number, number>, callback: testMapTransactionCallback): void
298    {
299        callback(0);
300    }
301    testArrayTransaction(data: string[], callback: testArrayTransactionCallback): void
302    {
303        callback(0, 1);
304    }
305}
306```
307
308在服务实现接口后,需要向客户端公开该接口,以便客户端进程绑定。如果开发者的服务要公开该接口,请扩展Ability并实现onConnect()从而返回IRemoteObject,以便客户端能与服务进程交互。服务端向客户端公开IRemoteAbility接口的代码示例如下:
309
310```ts
311import Want from '@ohos.app.ability.Want';
312import rpc from "@ohos.rpc";
313
314class ServiceAbility {
315  onStart() {
316    console.info('ServiceAbility onStart');
317  }
318  onStop() {
319    console.info('ServiceAbility onStop');
320  }
321  onCommand(want: Want, startId: number) {
322    console.info('ServiceAbility onCommand');
323  }
324  onConnect(want: Want) {
325    console.info('ServiceAbility onConnect');
326    try {
327      console.log('ServiceAbility want:' + typeof(want));
328      console.log('ServiceAbility want:' + JSON.stringify(want));
329      console.log('ServiceAbility want name:' + want.bundleName)
330    } catch(err) {
331      console.log('ServiceAbility error:' + err)
332    }
333    console.info('ServiceAbility onConnect end');
334    return new IdlTestImp('connect') as rpc.RemoteObject;
335  }
336  onDisconnect(want: Want) {
337    console.info('ServiceAbility onDisconnect');
338    console.info('ServiceAbility want:' + JSON.stringify(want));
339  }
340}
341
342export default new ServiceAbility()
343```
344
345#### 客户端调用IPC方法
346
347客户端调用connectServiceExtensionAbility()以连接服务时,客户端的onAbilityConnectDone中的onConnect回调会接收服务的onConnect()方法返回的IRemoteObject实例。由于客户端和服务在不同应用内,所以客户端应用的目录内必须包含.idl文件(SDK工具会自动生成Proxy代理类)的副本。客户端的onAbilityConnectDone中的onConnect回调会接收服务的onConnect()方法返回的IRemoteObject实例,使用IRemoteObject创建IdlTestServiceProxy类的实例对象testProxy,然后调用相关IPC方法。示例代码如下:
348
349```ts
350import common from '@ohos.app.ability.common';
351import Want from '@ohos.app.ability.Want';
352import IdlTestServiceProxy from './idl_test_service_proxy'
353
354function callbackTestIntTransaction(result: number, ret: number): void {
355  if (result == 0 && ret == 124) {
356    console.log('case 1 success');
357  }
358}
359
360function callbackTestStringTransaction(result: number): void {
361  if (result == 0) {
362    console.log('case 2 success');
363  }
364}
365
366function callbackTestMapTransaction(result: number): void {
367  if (result == 0) {
368    console.log('case 3 success');
369  }
370}
371
372function callbackTestArrayTransaction(result: number, ret: number): void {
373  if (result == 0 && ret == 124) {
374    console.log('case 4 success');
375  }
376}
377
378let onAbilityConnectDone: common.ConnectOptions = {
379  onConnect: (elementName, proxy) => {
380    let testProxy: IdlTestServiceProxy = new IdlTestServiceProxy(proxy);
381    let testMap: Map<number, number> = new Map();
382    testMap.set(1, 1);
383    testMap.set(1, 2);
384    testProxy.testIntTransaction(123, callbackTestIntTransaction);
385    testProxy.testStringTransaction('hello', callbackTestStringTransaction);
386    testProxy.testMapTransaction(testMap, callbackTestMapTransaction);
387    testProxy.testArrayTransaction(['1','2'], callbackTestMapTransaction);
388  },
389  onDisconnect: (elementName) => {
390    console.log('onDisconnectService onDisconnect');
391  },
392  onFailed: (code) => {
393    console.log('onDisconnectService onFailed');
394  }
395};
396
397let context: common.UIAbilityContext = this.context;
398
399function connectAbility(): void {
400    let want: Want = {
401        bundleName: 'com.example.myapplicationidl',
402        abilityName: 'com.example.myapplicationidl.ServiceAbility'
403    };
404    let connectionId = -1;
405    connectionId = context.connectServiceExtensionAbility(want, onAbilityConnectDone);
406}
407
408
409```
410
411#### IPC传递sequenceable对象
412
413开发者可以通过 IPC 接口,将某个类从一个进程发送至另一个进程。但是,必须确保 IPC 通道的另一端可使用该类的代码,并且该类必须支持marshalling和unmarshalling方法。系统需要通过marshalling和unmarshalling方法将对象序列化和反序列化成各进程能识别的对象。
414
415 **如需创建支持sequenceable 类型数据,开发者必须执行以下操作:**
416
4171. 实现marshalling方法,它会获取对象的当前状态并将其序列化后写入Parcel。
4182. 实现unmarshalling方法,它会从Parcel中反序列化出对象。
419
420MySequenceable类的代码示例如下:
421
422```ts
423import rpc from '@ohos.rpc';
424export default class MySequenceable implements rpc.Sequenceable {
425    constructor(num: number, str: string) {
426        this.num = num;
427        this.str = str;
428    }
429    getNum() : number {
430        return this.num;
431    }
432    getString() : string {
433        return this.str;
434    }
435    marshalling(messageParcel: rpc.MessageParcel) {
436        messageParcel.writeInt(this.num);
437        messageParcel.writeString(this.str);
438        return true;
439    }
440    unmarshalling(messageParcel: rpc.MessageParcel) {
441        this.num = messageParcel.readInt();
442        this.str = messageParcel.readString();
443        return true;
444    }
445    private num: number;
446    private str: string;
447}
448```
449
450### C++开发SA步骤(编译期自动生成SA接口模板代码)
451
452#### 创建.idl文件
453
454开发者使用C++编程语言构建.idl文件。
455
456例如,此处构建一个名为IQuickFixManager.idl的文件,文件内具体内容如下:
457
458```
459/*
460 * Copyright (c) 2023 Huawei Device Co., Ltd.
461 * Licensed under the Apache License, Version 2.0 (the "License");
462 * you may not use this file except in compliance with the License.
463 * You may obtain a copy of the License at
464 *
465 *     http://www.apache.org/licenses/LICENSE-2.0
466 *
467 * Unless required by applicable law or agreed to in writing, software
468 * distributed under the License is distributed on an "AS IS" BASIS,
469 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
470 * See the License for the specific language governing permissions and
471 * limitations under the License.
472 */
473
474sequenceable QuickFixInfo..OHOS.AAFwk.ApplicationQuickFixInfo;
475interface OHOS.AAFwk.IQuickFixManager {
476    void ApplyQuickFix([in] String[] quickFixFiles, [in] boolean isDebug);
477    void GetApplyedQuickFixInfo([in] String bundleName, [out] ApplicationQuickFixInfo quickFixInfo);
478    void RevokeQuickFix([in] String bundleName);
479}
480```
481
482#### 修改BUILD.gn文件
483
4841. 导入IDL工具模板到当前BUILD.gn文件。
485
486   ```bash
487   # 此处不需要修改,直接复制到gn中即可
488   import("//foundation/ability/idl_tool/idl_config.gni")
489   ```
490
4912. 调用IDL工具生成C++模板文件。
492
493   示例中的axx_bxx_cxx需要替换为生成的stub和proxy的.cpp名。
494
495   ```bash
496   idl_interface_sources = [
497     # axx_bxx_cxx为需要修改为生成proxy的.cpp名
498     "${target_gen_dir}/axx_bxx_cxx_proxy.cpp",
499     # axx_bxx_cxx为需要修改为生成stub的.cpp名
500     "${target_gen_dir}/axx_bxx_cxx_stub.cpp",
501   ]
502
503   # 使用idl_gen_interface生成模板文件、需输入参数名后面的deps中会使用
504   idl_gen_interface("EEEFFFGGG") {
505     # 开发者定义的.idl名,与gn文件在同一路径下
506     src_idl = rebase_path("IAxxBxxCxx.idl")
507     # proxy和stub模板.cpp文件, 此处不需要修改,直接复制到gn中即可
508     dst_file = string_join(",", idl_interface_sources)
509     # 开启hitrace,值是hitrace_meter.h文件中定义的uint64_t类型标识,需要填入常量的变量名
510     hitrace = "HITRACE_TAG_ABILITY_MANAGER"
511     # 开启hilog,Domain ID 使用16进制的整数
512     log_domainid = "0xD003900"
513     # 开启hilog,字符串类型tag名、一般为子系统名称
514     log_tag = "QuickFixManagerService"
515   }
516   ```
517
518   axx_bxx_cxx_proxy.cppaxx_bxx_cxx_stub.cpp的命名与.idl文件小写名相同,遇到大写时加"_"。
519
520   ```bash
521   # 例:.idl文件为IQuickFixManager.idl
522   axx_bxx_cxx_proxy.cpp为:quick_fix_manager_proxy.cpp
523   axx_bxx_cxx_stub.cpp为:quick_fix_manager_stub.cpp
524   ```
525
526   如果需要生成的模板文件名第一个字母为I时,需要在interface命名时在前面加一个I。
527
528   ```bash
529   # 例:生成的模板文件为quick_fix_manager_proxy.cpp时interface的名称应为IQuickFixManager
530   # .idl文件中的定义
531   interface OHOS.AAFwk.IQuickFixManager {
532       void ApplyQuickFix([in] String[] quickFixFiles, [in] boolean isDebug);
533       void GetApplyedQuickFixInfo([in] String bundleName, [out] ApplicationQuickFixInfo quickFixInfo);
534       void RevokeQuickFix([in] String bundleName);
535   }
536   ```
537
538   配置hilog,参数log_domainid和log_tag必须成对出现,若只写一个会编译错误。
539
540   ```bash
541   idl_gen_interface("quickfix_manager_interface") {
542     src_idl = rebase_path("IQuickFixManager.idl")
543     dst_file = string_join(",", idl_interface_sources)
544     hitrace = "HITRACE_TAG_ABILITY_MANAGER"
545     log_domainid = "0xD003900"
546     log_tag = "QuickFixManagerService"    #只有一个log_tag,编译会错误,同理只有log_domainid,编译也会错误
547   }
548   ```
549
5503. 在BUILD.gn中添加模板文件的头文件路径。
551
552   只需将“${target_gen_dir}”名添加到现有include_dirs中即可,其它不需要更改。
553
554   ```bash
555   include_dirs = [
556     "aaa/bbb/ccc",        # 原有头文件路径
557     "${target_gen_dir}",  # 模板头文件路径
558   ]
559   ```
560
5614. 在BUILD.gn中添加模板文件.cpp文件路径。
562
563   若sources中有axx_bxx_cxx_proxy.cppaxx_bxx_cxx_stub.cpp需要删除,并加上sources += filter_include(output_values, [ "*.cpp" ])。
564
565   ```bash
566   output_values = get_target_outputs(":EEEFFFGGG") # 返回给定目标标签的输出文件列表,替换EEEFFFGGG
567   sources = [ "axx_bxx_cxx_proxy.cpp" ]  # 需要删除axx_bxx_cxx_proxy.cpp
568   sources += filter_include(output_values, [ "*.cpp" ]) # filter_include选中符合的列表,直接复制即可
569   ```
570
5715. 在BUILD.gn中添加依赖“EEEFFFGGG”。
572
573   ```bash
574   deps = [
575       ":EEEFFFGGG",
576     ]
577   ```
578
579   deps添加的依赖名,必须同idl_gen_interface函数参数名相同。
580
581   ```bash
582   idl_gen_interface("quickfix_manager_interface") {
583     src_idl = rebase_path("IQuickFixManager.idl")
584     dst_file = string_join(",", idl_interface_sources)
585     hitrace = "HITRACE_TAG_ABILITY_MANAGER"
586     log_domainid = "0xD003900"
587     log_tag = "QuickFixManagerService"
588   }
589   deps = [
590    "${ability_runtime_innerkits_path}/app_manager:app_manager",
591    ":quickfix_manager_interface"]    # idl_gen_interface函数参数名相同
592   ```
593
5946. 在BUILD.gn中添加模板文件的外部依赖。
595
596   模板文件的外部依赖需要自己添加到external_deps里。
597
598   若之前已存在,不需要重复添加,若重复添加会导致编译错误。
599
600   ```bash
601     external_deps = [
602     # 模板文件必须的依赖
603     "c_utils:utils",
604     # hilog输出必须的依赖
605     "hilog:libhilog",
606     # hitrace输出必须的依赖
607     "hitrace:hitrace_meter",
608     # 模板文件必须的依赖
609     "ipc:ipc_core",
610   ]
611   ```
612
613#### 实例
614
615**以应用快速修复服务为例:**
616
6171. 创建名为IQuickFixManager.idl文件。
618
619   在创建.idl文件时,interface名称必须和.idl文件名相同,否则会在生成代码时出现错误。
620
621   创建.idl的文件路径与功能代码BUILD.gn的路径相同。
622
623   实例中的位置为:foundation/ability/ability_runtime/interfaces/inner_api/quick_fix/。
624
625   ```bash
626   /*
627    * Copyright (c) 2023 Huawei Device Co., Ltd.
628    * Licensed under the Apache License, Version 2.0 (the "License");
629    * you may not use this file except in compliance with the License.
630    * You may obtain a copy of the License at
631    *
632    *     http://www.apache.org/licenses/LICENSE-2.0
633    *
634    * Unless required by applicable law or agreed to in writing, software
635    * distributed under the License is distributed on an "AS IS" BASIS,
636    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
637    * See the License for the specific language governing permissions and
638    * limitations under the License.
639    */
640
641   sequenceable QuickFixInfo..OHOS.AAFwk.ApplicationQuickFixInfo;
642   interface OHOS.AAFwk.IQuickFixManager {
643       void ApplyQuickFix([in] String[] quickFixFiles, [in] boolean isDebug);
644       void GetApplyedQuickFixInfo([in] String bundleName, [out] ApplicationQuickFixInfo quickFixInfo);
645       void RevokeQuickFix([in] String bundleName);
646   }
647   ```
648
649   在创建.idl文件时,需要将返回值为int的函数,修改为void。
650
651   ```bash
652   # 例 quick_fix_manager_client.h中的函数
653       int32_t ApplyQuickFix(const std::vector<std::string> &quickFixFiles);
654       int32_t GetApplyedQuickFixInfo(const std::string &bundleName, ApplicationQuickFixInfo &quickFixInfo);
655       int32_t RevokeQuickFix(const std::string &bundleName);
656   # .idl文件中的定义
657   interface OHOS.AAFwk.QuickFixManager {
658       void ApplyQuickFix([in] String[] quickFixFiles);
659       void GetApplyedQuickFixInfo([in] String bundleName, [out] ApplicationQuickFixInfo quickFixInfo);
660       void RevokeQuickFix([in] String bundleName);
661   }
662   ```
663
6642. 修改BUILD.gn文件。
665
666   ```bash
667   # Copyright (c) 2023 Huawei Device Co., Ltd.
668   # Licensed under the Apache License, Version 2.0 (the "License");
669   # you may not use this file except in compliance with the License.
670   # You may obtain a copy of the License at
671   #
672   #     http://www.apache.org/licenses/LICENSE-2.0
673   #
674   # Unless required by applicable law or agreed to in writing, software
675   # distributed under the License is distributed on an "AS IS" BASIS,
676   # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
677   # See the License for the specific language governing permissions and
678   # limitations under the License.
679
680   import("//build/ohos.gni")
681   import("//foundation/ability/ability_runtime/ability_runtime.gni")
682   import("//foundation/ability/idl_tool/idl_config.gni")
683
684   idl_interface_sources = [
685     "${target_gen_dir}/quick_fix_manager_proxy.cpp",
686     "${target_gen_dir}/quick_fix_manager_stub.cpp",
687   ]
688
689   idl_gen_interface("quickfix_manager_interface") {
690     src_idl = rebase_path("IQuickFixManager.idl")
691     dst_file = string_join(",", idl_interface_sources)
692     hitrace = "HITRACE_TAG_ABILITY_MANAGER"
693     log_domainid = "0xD003900"
694     log_tag = "QuickFixManagerService"
695   }
696
697   config("quickfix_config") {
698     visibility = [ ":*" ]
699     include_dirs = [
700       "include",
701       "${target_gen_dir}",
702     ]
703     cflags = []
704     if (target_cpu == "arm") {
705       cflags += [ "-DBINDER_IPC_32BIT" ]
706     }
707   }
708
709   ohos_shared_library("quickfix_manager") {
710     configs = [ "${ability_runtime_services_path}/common:common_config" ]
711     public_configs = [ ":quickfix_config" ]
712
713     output_values = get_target_outputs(":quickfix_manager_interface")
714     sources = [
715       "src/quick_fix_error_utils.cpp",
716       "src/quick_fix_info.cpp",
717       "src/quick_fix_load_callback.cpp",
718       "src/quick_fix_manager_client.cpp",
719       "src/quick_fix_utils.cpp",
720     ]
721     sources += filter_include(output_values, [ "*.cpp" ])
722     defines = [ "AMS_LOG_TAG = \"QuickFixService\"" ]
723     deps = [
724       ":quickfix_manager_interface",
725       "${ability_runtime_innerkits_path}/app_manager:app_manager",
726     ]
727
728     external_deps = [
729       "ability_base:want",
730       "bundle_framework:appexecfwk_base",
731       "bundle_framework:appexecfwk_core",
732       "c_utils:utils",
733       "hilog:libhilog",
734       "hitrace:hitrace_meter",
735       "ipc:ipc_single",
736       "safwk:system_ability_fwk",
737       "samgr:samgr_proxy",
738     ]
739
740     innerapi_tags = [ "platformsdk" ]
741     subsystem_name = "ability"
742     part_name = "ability_runtime"
743   }
744   ```
745
7463. 生成模板文件的路径及目录结构。
747
748   编译以rk3568为例,实例中生成的模板文件路径为:out/rk3568/gen/foundation/ability/ability_runtime/interfaces/inner_api/quick_fix/。
749
750   其中foundation/ability/ability_runtime/interfaces/inner_api/quick_fix/为.idl文件所在的相对路径。
751
752   生成文件目录结构为:
753
754   ```bash
755   |-- out/rk3568/gen/foundation/ability/ability_runtime/interfaces/inner_api/quick_fix/
756      |-- iquick_fix_manager.h
757      |-- quick_fix_manager_stub.h
758      |-- quick_fix_manager_stub.cpp
759      |-- quick_fix_manager_proxy.h
760      |-- quick_fix_manager_proxy.cpp
761   ```
762
763
764## 相关实例
765
766针对IDL的使用,有以下相关实例可供参考:
767
768- [Ability与ServiceExtensionAbility通信(ArkTS)(Full SDK)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/IDL/AbilityConnectServiceExtension)