接口描述语言简介
当客户端和服务器通信时,需要定义双方都认可的接口,以保障双方可以成功通信,HarmonyOSIDL则是一种定义此类接口的工具。HarmonyOSIDL先把需要传递的对象分解成操作系统能够理解的基本类型,并根据开发者的需要封装跨边界的对象。在HarmonyOS中,HarmonyOSIDL接口包含面向应用程序的北向接口和面向硬件设备的南向接口。HarmonyOSIDL接口描述语言:
HarmonyOSIDL接口描述语言主要用于:声明系统服务对外提供的服务接口,根据接口声明在编译时生成跨进程调用或跨设备调用的代理和桩的C/C++代码或Java代码。声明Ability对外提供的服务接口,根据接口声明在编译时生成跨进程调用或跨设备调用的代理和桩的C/C++代码或Java代码。IPC/RPC通信模型如下:
使用HarmonyOSIDL接口描述语言声明接口具有以下优点:HarmonyOSIDL中是以接口的形式定义服务,可以专注于定义而隐藏实现细节。HarmonyOSIDL中定义的接口可以支持跨进程调用或跨设备调用,根据HarmonyOSIDL中的定义生成的信息或代码可以简化跨进程或跨设备调用接口的实现。采用HarmonyOSIDL描述的接口代码示例如下:
interface ohos.app.IAbilityConnection;
interface ohos.os.IBroker;
sequenceable ohos.content.AbilityInfo;
sequenceable ohos.content.Intent;
interface ohos.app.IAbilityManager {
int StartAbility([in] Intent intent);
void SetAbilitySliceCallback([in] IBroke broker, [in] IAbilityConnection callback);
[oneway]
void ExitAbility([in] AbilityInfo abilityInfo);
}
接口描述语言构成
数据类型
HarmonyOSIDL支持的数据类型可分为:基本数据类型、自定义类型、声明的Sequenceable数据类型、声明的接口类型、数组类型以及容器类型。HarmonyOSIDL基本数据类型与Java数据类型、C/C++数据类型的对应关系如下表所示:
void | void | void | void | NA |
boolean | boolean | bool | bool | 1 |
byte | byte | int8_t | int8_t | 1 |
short | short | int16_t | int16_t | 2 |
int | int | int32_t | int32_t | 4 |
long | long | int64_t | int64_t | 8 |
float | float | float | float | 4 |
double | double | double | double | 8 |
String | String | std::string | cstring | NA |
unsigned char | 不支持 | uint8_t | uint8_t | 1 |
unsigned short | 不支持 | uint16_t | uint16_t | 2 |
unsigned int | 不支持 | uint32_t | uint32_t | 4 |
unsigned long | 不支持 | uint64_t | uint64_t | 8 |
自定义类型是指使用关键字struct、union、enum定义的结构体类型、联合体类型、枚举类型,以及这些类型组合嵌套定义的类型。自定义类型文件MyTypes.idl示例如下:
struct Example1 {
String member1;
unsigned int member2;
};
union Example2 {
String member1;
unsigned int member2;
};
enum Example3 : int {
RED,
BLUE,
GREEN,
};
struct Example1_2_3 {
struct Example1;
union Example2;
enum Example3;
};
在定义枚举类型时,需要指定枚举类型的基本数据类型,可以使用byte、short、int、long、unsignedchar、unsignedshort、unsignedint、unsignedlong。如果未指定,则默认基础类型为int类型。一个模块在定义HarmonyOSIDL接口时使用的自定义类型应该定义在一个独立的文件中,不要分散到每个接口定义的文件中。自定义类型所在文件的名称可以根据实际情况进行定义,在接口定义文件中需要导入自定义类型文件,例如:MyInterfacidl接口使用了MyTypes.idl中定义的自定义类型,代码示例如下:
HarmonyOSIDL自定义数据类型与Java数据类型、C/C++数据类型的对应关系如下表所示:
struct | 不支持 | struct | struct |
union | 不支持 | union | union |
enum | 不支持 | enum | enum |
Sequenceable数据类型是指用“Sequenceable”关键字声明的非基本数据类型,表明该数据类型可以通过Parcel进行跨进程传递。声明放在文件的头部,形式为“sequenceablenamespactypename;”,namespace是该类型所属的命名空间,内部采用“.”连接不同层级的命名空间,typename是类型名。例如:“sequenceablecohuawesamples.ApplicationInfo;”表示ApplicationInfo类型可以通过Parcel进行跨进程传递。Sequenceable数据类型并不在HarmonyOSIDL文件中定义,而是定义在C++文件或Java文件中,C语言文件不支持。HarmonyOSIDL工具将根据声明在生成的C++代码文件中加入“#include“com/huawei/samples/ApplicationInfo.h””语句,在生成的Java代码文件中加入“importcohuawesamples.ApplicationInfo;”语句。HarmonyOSIDLSequenceable数据类型与Java数据类型、C/C++数据类型的对应关系如下表所示:
Sequenceable | sequenceable namespace.typename; 例如:sequenceable com.huawei.samples.ApplicationInfo; | #include namespace/typename.h' using namespace::typename 例如:#include com/huawei/samples/ApplicationInfo.h' using com::huawei::samples::ApplicationInfo | 不支持 |
接口类型是指HarmonyOSIDL文件中定义的接口。对于当前IDL文件中定义的接口,可以直接使用它作为方法参数类型或返回值类型。而在其它HarmonyOSIDL文件中定义的接口,则需要在文件的头部进行前置声明。声明的形式为“interfacenamespacinterfacename;”,namespace是该接口所属的命名空间,内部采用“.”连接不同层级的命名空间,interfacename是接口名。例如:“interfacecohuawesamples.IApplication;”声明了在其他HarmonyOSIDL文件定义的IApplication接口,该接口可以作为当前定义中方法的参数类型或返回值类型使用。HarmonyOSIDL工具将根据该声明在生成的C++代码文件中加入“#include“com/huawei/samples/IApplicatioh””语句,在生成的Java代码文件中加入“importcohuawesamples.IApplication;”语句。IBroker也是接口类型的一种,使用它无需前置声明。HarmonyOSIDL接口数据类型与Java数据类型、C/C++数据类型的对应关系如下表所示:
Interface | sequenceable namespace.interfacename; 例如:sequenceable com.huawei.samples.IApplication; | #include namespace/interfacename.h' using namespace::interfacename; 例如:#include com/huawei/samples/IApplication.h' using com::huawei::samples::IApplication; | 不支持 |
数组类型用“T[]”表示,T可以是基本数据类型、自定义类型、Sequenceable数据类型、接口类型和数组类型。在C++代码中,数组类型生成为std::vector,在Java代码中,数组类型生成为T[]。HarmonyOSIDL数组数据类型与Java数据类型、C/C++数据类型的对应关系如下表所示:
T[] | T[] | std::vector | T*,int size |
容器类型当前支持两种容器:List和Map。List容器用法为“List”,Map容器用法为“Map
List | List | std::list或std::vector | T*,int size |
Map<KT, VT> | HashMap | std::map或std::unordered map | 不支持 |
接口定义
一个HarmonyOSIDL文件只能定义一个接口类,接口定义的形式使用BNF范式描述,示例如下:
<*interface_attributes_declaration*> ? interface <*interface_name_with_namespace*> { <*method_declaration*> ? }
[ <*formal_parameter_attribute*> ] <*type*> <*identifier*>
void SetBundles([in] Map bundleInfos, [in, out] int number);
[oneway] void Dump([in] ParcelableFileDescriptor fd, [in] long flags);
在HarmonyOSIDL接口描述文件中可以使用的关键字如下表所示:
void、boolean、byte、short、int、long、float、double | 基本数据类型,void类型、bool型、整型、浮点型等 |
unsigned | 在定义无符号类型时使用,如unsigned char、unsigned short、unsigned int、unsigned long |
String | 定义字符串时使用 |
struct | 结构体类型 |
union | 联合体类型 |
enum | 枚举类型 |
T[] | T可以是基本数据类型、自定义类型、Sequenceable数据类型、接口类型和数组类型 |
List<> | 容器类型List,T为基本数据类型、自定义类型、Sequenceable类型、接口类型、数组类型或容器类型 |
Map<> | 容器类型Map<KT, VT>: KT和VT为基本数据类型、自定义类型、Sequenceable类型、接口类型、数组类型或容器类型 |
Sequenceable | 该类型并不在idl文件中定义,而是定义在C++文件或Java文件中 |
extends | 接口继承 |
interface | 接口类型 |
[oneway] | 表示单向接口或方法 oneway方法不允许有输出参数(包含输入输出参数)和返回值 |
[in] | 输入参数 |
[out] | 输出参数 |
[inout] | 输入输出参数 |
[callback] | 标识一个接口为回调接口定义(明示工具如何生成service、client代码) |
[full] | 仅在HarmonyOS重量级部署中使用的参数、接口、方法 |
[lite] | 仅在HarmonyOS轻量级部署中使用的参数、接口、方法 |
注释说明
HarmonyOSIDL文件中的注释采用与C/C++相同的方式,可以采用//或者/*…*/的方式进行注释说明。
开发步骤
创建.idl文件
可以使用Java或C++编程语言构建.idl文件。.idl示例如下:
sequenceable com.example
/** Example service ability interface */
interface com.example.IRemoteAbility {
int plus([in] int num1, [in] int num2);
}
服务端公开接口
HarmonyOSIDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法:
public abstract class RemoteAbilityStub extends RemoteObject implements IRemoteAbility {
private static final String DESCRIPTOR = 'com.example.IRemoteAbility';
private static final int COMMAND_PLUS = IRemoteObject.MIN_TRANSACTION_ID + 0;
………
}
要实现.idl生成的接口,请扩展生成的RemoteObject接口,并实现继承自.idl文件的方法。MyRemote定义了服务的远程过程调用接口,示例代码如下:
class MyRemote extends RemoteAbilityStub {
public MyRemote(String descriptor) {
super(descriptor);
}
@Override
public int plus(int num1, int num2) throws RemoteException {
return num1 + num2;
}
}
在服务实现接口后,需要向客户端公开该接口,以便客户端进程绑定。如果开发者的服务要公开该接口,请扩展Ability并实现onConnect()从而返回IRemoteObject,以便客户端能与服务进程交互。服务端向客户端公开IRemoteAbility接口的代码示例如下:
public class ServiceAbility extends Ability {
private MyRemote remote = new MyRemote('MyRemoteAbility');
class MyRemote extends RemoteAbilityStub {
public MyRemote(String descriptor) {
super(descriptor);
}
@Override
public int plus(int num1, int num2) throws RemoteException {
return num1 + num2;
}
}
@Override
public IRemoteObject onConnect(Intent intent) {
return remote.asObject();
}
}
客户端调用IPC方法
IRemoteAbility proxy;
private IAbilityConnection conn = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName element, IRemoteObject remote, int resultCode) {
proxy = IRemoteAbilityStub.asInterface(remote);
}
@Override
public void onAbilityDisconnectDone(ElementName element, int resultCode) {
proxy = null;
}
};
如果要断开连接,请调用Ability.disconnectAbility()。
④IPC传递Sequenceable对象
开发者可以通过IPC接口,将某个类从一个进程发送至另一个进程。必须确保IPC通道的另一端可使用该类的代码,并且该类必须支持Sequenceable接口。HarmonyOS需要通过该Sequenceable接口将对象反序列化成各进程能识别的对象。如需创建支持Sequenceable接口的类,开发者必须执行以下操作:自定义对象实现Sequenceable接口;实现marshalling方法,它会获取对象的当前状态并将其序列化后写入Parcel;实现unmarshalling方法,它会从Parcel中反序列化出对象;ElementNamjava类实现Sequenceable接口的代码示例如下:
public class ElementName implements Sequenceable {
private String deviceId = '';
private String bundleName = '';
private String abilityName = '';
public ElementName() {
}
public ElementName(String deviceId, String bundleName, String abilityName) {
this.deviceId = deviceId;
this.bundleName = bundleName;
this.abilityName = abilityName;
}
@Override
public boolean marshalling(Parcel out) {
if (!out.writeString(bundleName)) {
return false;
}
if (!out.writeString(abilityName)) {
return false;
}
if (!out.writeString(deviceId)) {
return false;
}
return true;
}
@Override
public boolean unmarshalling(Parcel in) {
this.bundleName = in.readString();
this.abilityName = in.readString();
this.deviceId = in.readString();
return true;
}
IDL语法规则
HarmonyOS IDL语法规则(BNF范式描述) | HarmonyOS IDL语法规则(文字描述) | 示例 |
---|---|---|
### Programs | 一个HarmonyOS IDL接口定义文件由三部分组成:包名、类型声明、接口定义。 IDL接口文件扩展名为*.idl。 一个文件只能定义一个接口,多个接口需要定义在多个不同的文件中。 文件名必须和接口名一致。 自定义类型单独成一个文件,该文件名可以按需定义。 | - |
<*package_declaration*> :: = package <*package_name_with_namespace*> ; | 包名 | package ohos.app; |
<*package_name_with_namespace*> ::= <*namespace*> . <*package_name*> | <*package_name*> | - | - |
<*type_declarations*> ::= <*java_like_type_declarations*> | <*c_like_type_declarations*> | 类型声明 | - |
<*java_like_type_declarations*> ::= <*sequenceable_class_declaration*>? <*package_type_declaration*>? <*interface_declaration*>? | 类Java语言的类型声明,包括:sequenceable类型声明、包类型声明、接口类型声明 | - |
<*sequenceable_class_declaration*> ::= sequenceable <*sequenceable_class_name_with_namespace*> ; | sequenceable类型声明 | sequenceable ohos.content.AbilityInfo; |
<*sequenceable_class_name_with_namespace*> ::= <*namespace*> . <*sequenceable_class_name*> | <*sequenceable_class_name*> | - | - |
<*c_like_type_declarations*> ::= <*package_type_declaration*>? <*custom_type_declaration*>? <*interface_declaration*>? | 类C语言的类型声明,包括包类型声明、自定义类型声明、接口类型声明 | - |
<*custom_type_file_name_with_namespace*> ::= <*namespace*> . <*custom_type_file_name*> | <*custom_type_file_name*> | - | - |
<*interface_declaration*> ::= interface <*interface_name_with_namespace*> ; | 接口类型声明 | interface ohos.app.IAbilitySliceConnection; |
<*interface_name_with_namespace*> ::= <*namespace*> . <*interface_name*> | <*interface_name*> | - | - |
<*interface_definition*> ::= <*interface_attributes_declaration*>? interface <*interface_name_with_namespace*> <*interface_inheritance_declaration*>? { <*method_declaration*>+ }; | 接口定义,包括:接口属性、接口名称、接口继承声明、接口函数 | interface ohos.app.IAbilityManager { int StartAbility([in] Intent intent); …… }; |
<*interface_attributes_declaration*> ::= [ <*interface_attributes*> ] | 接口属性 | - |
<*interface_attributes*> ::= <*interface_attribute*> | <*interface_attributes*> , <*interface_attribute*> | - | - |
<*interface_attribute*> ::= <*java_like_interface_attribute*> | <*c_like_interface_attribute*> | - | - |
<*java_like_interface_attribute*> ::= oneway | 类Java语言的属性支持:oneway | - |
<*c_like_interface_attribute*> ::= <*java_like_interface_attribute*> | callback | full | lite | 类C语言的属性,支持:oneway、callback、full、lite | - |
<*interface_inheritance_declaration*> ::= extends <*parent_interface_name_with_namespace*> | 接口继承声明 | interface ohos.app.IAbilityManager extends ohos.app.IManager { …… }; |
<*parent_interface_name_with_namespace*> ::= <*interface_name_with_namespace*> | 父接口 | - |
<*method_declaration*> ::= <*method_attributes_declaration*>? <*result_type*> <*method_declarator*> ; | 接口函数声明,包括:函数属性、返回值、函数名称、参数列表 | - |
<*method_attributes_declaration*> ::= [ <*method_attributes*> ] | 函数属性 | - |
<*method_attributes*> ::= <*method_attribute*> | <*method_attributes*> , <*method_attribute*> | - | - |
<*method_attribute*> ::= <*java_like_method_attribute*> | <*c_like_method_attribute*> | - | - |
<*java_like_method_attribute*> ::= oneway | 类Java语言的函数属性支持:oneway | - |
<*c_like_method_attribute*> ::= <*java_like_method_attribute*> | full | lite | 类C语言的函数属性,支持:oneway、full、lite | - |
<*result_type*> ::= <*type*> | void | 返回值:可以没有返回值(void),返回一个指定类型的值 | - |
<*method_declarator*> ::= <*method_name*> ( <*formal_parameters*>? ) | 接口函数:可以没有参数 | - |
<*formal_parameters*> ::= <*formal_parameter*> | <*formal_parameters*> , <*formal_parameter*> | - | - |
<*formal_parameter*> ::= [ <*formal_parameter_attribute*> ] <*type*> <*formal_parameter_name*> | 每个函数参数由三个部分组成:参数属性、参数类型、参数名称 | - |
<*formal_parameter_attribute*> ::= in | out | inout | <参数属性,支持:in、out、inout/th> | - |
### Types | - | - |
<*type*> ::= <*java_like_type*> | <*c_like_type*> | - | - |
<*java_like_type*> ::= <*primitive_type*> | <*string_type*> | <*sequenceable_type*> | <*interface_type*> | <*list_type*> | <*map_type*> | <*array_type*> | 类Java语言的数据类型,包括:基本类型、String类型、sequenceable类型、接口类型、List容器类型、Map容器类型、数组类型 | - |
<*c_like_type*> ::= <*primitive_type*> | <*string_type*> | <*interface_type*> | <*list_type*> | <*array_type*> | <*custom_type*> | 类C语言的数据类型,包括:基本类型、String类型、接口类型、List容器类型、数组类型、自定义类型 | - |
<*primitive_type*> ::= <*java_like_primitive_type*> | <*c_like_primitive_type*> | - | - |
<*java_like_primitive_type*> ::= boolean | byte | short | int | long | float | double | 类Java语言的基本类型 | - |
<*c_like_primitive_type*> ::= <*java_like_primitive_type*> | unsigned char | unsigned short | unsigned int | unsigned long | 类C语言的基本类型:除类Java语言的基本类型外,还可以使用无符号类型 | - |
<*string_type*> ::= String | String类型 | - |
<*sequenceable_type*> ::= <*sequenceable_class_name*> | sequenceable类型 | - |
<*interface_type*> ::= <*interface_name*> | interface接口类型 | - |
<*list_type*> ::= List < <*type*> > | <*list_type*> ::= List < <*type*> > | - |
<*map_type*> ::= Map < <*type*> , <*type*> > | Map容器类型 | - |
<*array_type*> ::= <*type*> [ ] | 数组类型 | - |
<*custom_type*> ::= <*enum_type*> | <*struct_type*> | <*union_type*> | 自定义类型,包括:枚举类型、结构体类型、联合体类型、三种类型的嵌套使用 | - |
<*enum_type*> ::= <*custom_type_attributes_declaration*>? enum <*custom_type_name*> { <*enum_members_declaration*>+ }; | 枚举类型:自定义类型属性、类型名、枚举成员 | - |
<*struct_type*> ::= <*custom_type_attributes_declaration*>? struct <*custom_type_name*> { <*custom_type_members_declaration*>+ }; | 结构体类型:自定义类型属性、类型名、结构体成员 | - |
<*union_type*> ::= <*custom_type_attributes_declaration*>? union <*custom_type_name*> { <*custom_type_members_declaration*>+ }; | 联合体类型:自定义类型属性、类型名、联合体成员 | - |
<*custom_type_attributes_declaration*> ::= [ <*custom_type_attributes*> ] | - | - |
<*custom_type_attributes*> ::= <*custom_type_attribute*> | <*custom_type_attributes*> , <*custom_type_attribute*> | - | - |
<*custom_type_attribute*> ::= full | lite | 自定义类型的属性,支持:full、lite | - |
<*enum_members_declaration*> ::= <*custom_type_attributes_declaration*>? <*enum_member_name*> <*enum_member_value*>? , | 枚举类型成员:自定义类型属性、枚举成员名、枚举成员值(可选) | - |
<*enum_member_value*> ::= = <*number_value*> | 枚举成员值 | - |
<*custom_type_members_declaration*> ::= <*primitive_type_member*> | <*list_type_member*> | <*array_type_member*> | <*custom_type_member*> | 自定义类型成员,支持:基本类型、List容器类型、数组类型、自定义类型 | - |
<*primitive_type_member*> ::= <*custom_type_attributes_declaration*>? <*c_like_primitive_type*> <*custom_type_member_name*> ; | 基本类型成员:自定义类型属性、数据类型、自定义成员变量名 | - |
<*list_type_member*> ::= <*custom_type_attributes_declaration*>? <*custom_list_type*> <*custom_type_member_name*> ; | List容器类型成员:自定义类型属性、数据类型、自定义成员变量名 | - |
<*array_type_member*> ::= <*custom_type_attributes_declaration*>? <*custom_array_type*> <*custom_type_member_name*> ; | 数组类型成员:自定义类型属性、数据类型、自定义成员变量名 | - |
<*custom_type_member*> ::= <*custom_type_attributes_declaration*>? <*custom_type*> <*custom_type_member_name*> ; | 自定义类型成员:自定义类型属性、数据类型、自定义成员变量名 | - |
<*custom_list_type*> ::= List < <*custom_member_type*> > | 自定义类型中使用的List容器类型 | - |
<*custom_array_type*> ::= <*custom_member_type*> [ ] | 自定义类型中使用的数组类型 | - |
<*custom_member_type*> ::= <*c_like_primitive_type*> | <*string_type*> | <*custom_type*> | 自定义成员类型:类C语言的基本类型、字符串类型、自定义类型、不支持接口类型、Map容器类型等 | - |
### Tokens | - | - |
<*package_name*> ::= <*identifier*> | 包名 | - |
<*custom_type_file_name*> ::= <*identifier*> | 自定义类型所在的文件名 | - |
<*namespace*> ::= <*identifier*> | <*namespace*> . <*identifier*> | 命名空间 | - |
<*sequenceable_class_name*> ::= <*identifier*> | sequenceable类名 | - |
<*interface_name*> ::= <*identifier*> | 接口名 | - |
<*method_name*> ::= <*identifier*> | 接函数口名 | - |
<*formal_parameter_name*> ::= <*identifier*> | 参数名 | - |
<*custom_type_name*> ::= <*identifier*> | 自定义类型名 | - |
<*enum_member_name*> ::= <*enum_letter*>+ | 枚举成员名 | - |
<*custom_type_member_name*> ::= <*identifier*> | 自定义类型成员名 | - |
### identifier | - | - |
<*identifier*> ::= <*letter*>+ | <*letter_number*> | 标识符由字母和数字组成,第一个字符不能使用数字 | - |
<*letter*> ::= _ | <*upper_case*> | <*lower_case*> | 字符,包括:下滑线、大写字母、小写字母 | - |
<*letter_number*> ::= <*letter*>+ | <*letter_number*> <*letter*> | <*letter_number*> <*number*> | - | - |
<*upper_case*> ::= A|B|C|D|E|F|G|H|I|J …… | - | - |
<*lower_case*> ::= a|b|c|d|e|f|g|h|i|j …… | - | - |
<*number*> ::= <*dec_number*> | - | - |
<*dec_number*> ::= <*oct_number*> | 8 | 9 | 十进制数字 | - |
<*oct_number*> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 八进制数字 | - |
<*number_value*> ::= <*hex_prefix*> <*hex_value*> | <*dec_value*> | 0 <*oct_value*> | 数值:枚举类型成员的值 | - |
<*hex_prefix*> ::= 0x | 0X | - | - |
<*hex_value*> ::= <*hex_number*>+ | - | - |
<*dec_value*> ::= <*dec_number*>+ | - | - |
<*oct_value*> ::= <*oct_number*>+ | - | - |
<*hex_number*> ::= <*dec_number*> | A | B | C | D | E | F | a | b | c | d | e | f | 十六进制数字 | - |
<*enum_letter*> ::= _ | <*upper_case*> | 枚举类型成名的命名,可以使用:下滑线、大写字母 | - |
语法文档使用的规则如下:尖括号<>内包含的为必选项;竖线|表示在其左右两边任选一项,相当于'OR'的含义;::=是“被定义为”的含义;?操作符左边的符号是可选项;“+1”次或多次;[或]是左右中括号字符本身。
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点