diff --git a/zh-cn/application-dev/IDL/figures/SDKpath.png b/zh-cn/application-dev/IDL/figures/SDKpath.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7e33f0246e07fa9f6b8aeb0677c7159dfceb3d Binary files /dev/null and b/zh-cn/application-dev/IDL/figures/SDKpath.png differ diff --git a/zh-cn/application-dev/IDL/figures/SDKpath2.png b/zh-cn/application-dev/IDL/figures/SDKpath2.png new file mode 100644 index 0000000000000000000000000000000000000000..51ac48d2f04d876a204493415b79a5f12e183685 Binary files /dev/null and b/zh-cn/application-dev/IDL/figures/SDKpath2.png differ diff --git a/zh-cn/application-dev/IDL/idl-guidelines.md b/zh-cn/application-dev/IDL/idl-guidelines.md index 5aa1a084c0bc9d4a28e5504cd29f11954a46fa21..bfe58e47f7190b2283517655d1b9f88ad9134893 100644 --- a/zh-cn/application-dev/IDL/idl-guidelines.md +++ b/zh-cn/application-dev/IDL/idl-guidelines.md @@ -149,198 +149,53 @@ OpenHarmony IDL容器数据类型与Ts数据类型、C++数据类型的对应关 ## 开发步骤 -### C++开发步骤 +### IDL工具的获取 +首先,打开DevEco Studio—>Tools—>SDK Manager,查看OpenHarmony SDK的本地安装路径,此处以DevEco Studio 3.0.0.993版本为例,查看方式如下图所示。 +![SDKpath](./figures/SDKpath.png) +![SDKpath](./figures/SDKpath2.png) -#### 创建.idl文件 - - 开发者可以使用C++编程语言构建.idl文件。.idl示例如下: +进入对应路径后,查看toolchains->3.x.x.x(对应版本号命名文件夹)下是否存在idl工具的可执行文件。 -```cpp - interface OHOS.IIdlTestService { - int TestIntTransaction([in] int data); - void TestStringTransaction([in] String data); - } -``` +> **注意**:请保证使用最新版的SDK,版本老旧可能导致部分语句报错。 -使用者通过执行命令 “./idl -gen-cpp -d dir -c dir/iTest.idl” (-d为输出目录)在执行环境的dir目录中生成接口文件、Stub文件、Proxy文件。生成的接口类文件名称和.idl文件名称保持一致,区别在于其使用.h和.cpp扩展名。例如,IIdlTestService.idl 生成的文件名是 i_idl_test_service.h、idl_test_service_proxy.h、idl_test_service_stub.h、idl_test_service_proxy.cpp、idl_test_service_stub.cpp。 +若不存在,可对应版本前往[docs仓版本目录](https://gitee.com/openharmony/docs/tree/master/zh-cn/release-notes)下载SDK包,以[3.2Beta3版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.2-beta3.md#%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96)为例,可通过镜像站点获取。 -#### 服务端公开接口 +关于如何替换DevEco Studio的SDK包具体操作,参考[full-SDK替换指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/full-sdk-switch-guide.md#full-sdk%E6%9B%BF%E6%8D%A2%E6%8C%87%E5%8D%97)中的替换方法。 -OpenHarmony IDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法。 +得到idl工具的可执行文件后,根据具体场景进行后续开发步骤。 -```cpp -#ifndef OHOS_IDLTESTSERVICESTUB_H -#define OHOS_IDLTESTSERVICESTUB_H -#include -#include "iidl_test_service.h" - -namespace OHOS { -class IdlTestServiceStub : public IRemoteStub { -public: - int OnRemoteRequest( - /* [in] */ uint32_t code, - /* [in] */ MessageParcel& data, - /* [out] */ MessageParcel& reply, - /* [in] */ MessageOption& option) override; - -private: - static constexpr int COMMAND_TEST_INT_TRANSACTION = MIN_TRANSACTION_ID + 0; - static constexpr int COMMAND_TEST_STRING_TRANSACTION = MIN_TRANSACTION_ID + 1; -}; -} // namespace OHOS -#endif // OHOS_IDLTESTSERVICESTUB_H -``` +### TS开发步骤 -开发者需要继承.idl文件中定义的接口类并实现其中的方法,同时在服务侧初始化时需要将定义的服务注册至SAMGR中,在本示例中,TestService类继承了IdlTestServiceStub接口类并实现了其中的TestIntTransaction和TestStringTransaction方法。具体的示例代码如下: +#### 创建.idl文件 -```cpp -#ifndef OHOS_IPC_TEST_SERVICE_H -#define OHOS_IPC_TEST_SERVICE_H - -#include "hilog/log.h" -#include "log_tags.h" -#include "idl_test_service_stub.h" - -namespace OHOS { -class TestService : public IdlTestServiceStub { -public: - TestService(); - ~TestService(); - static int Instantiate(); - ErrCode TestIntTransaction(int data, int &rep) override; - ErrCode TestStringTransaction(const std::string& data) override; -private: - static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestService" }; -}; -} // namespace OHOS -#endif // OHOS_IPC_TEST_SERVICE_H -``` + 开发者可以使用TS编程语言构建.idl文件。 -注册服务的示例代码如下: + 例如,此处构建一个名为IIdlTestService.idl的文件,文件内具体内容如下: ```cpp -#include "test_service.h" - -#include - -#include "if_system_ability_manager.h" -#include "ipc_debug.h" -#include "ipc_skeleton.h" -#include "iservice_registry.h" -#include "system_ability_definition.h" - -namespace OHOS { -using namespace OHOS::HiviewDFX; - -int TestService::Instantiate() -{ - ZLOGI(LABEL, "%{public}s call in", __func__); - auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (saMgr == nullptr) { - ZLOGE(LABEL, "%{public}s:fail to get Registry", __func__); - return -ENODEV; - } - - sptr newInstance = new TestService(); - int result = saMgr->AddSystemAbility(IPC_TEST_SERVICE, newInstance); - ZLOGI(LABEL, "%{public}s: IPC_TEST_SERVICE result = %{public}d", __func__, result); - return result; -} - -TestService::TestService() -{ -} - -TestService::~TestService() -{ -} - -ErrCode TestService::TestIntTransaction(int data, int &rep) -{ - ZLOGE(LABEL, " TestService:read from client data = %{public}d", data); - rep = data + data; - return ERR_NONE; -} - -ErrCode TestService::TestStringTransaction(const std::string &data) -{ - ZLOGE(LABEL, "TestService:read string from client data = %{public}s", data.c_str()); - return data.size(); -} -} // namespace OHOS + interface OHOS.IIdlTestService { + int TestIntTransaction([in] int data); + void TestStringTransaction([in] String data); + } ``` -#### 客户端调用IPC方法 - -C++客户端通常通过SAMGR获取系统中定义的服务代理,随后即可正常调用proxy提供的接口。示例代码如下: +在idl的可执行文件所在文件夹下执行命令 `idl -gen-ts -d dir -c dir/IIdlTestService.idl`。 -```cpp -#include "test_client.h" - -#include "if_system_ability_manager.h" -#include "ipc_debug.h" -#include "ipc_skeleton.h" -#include "iservice_registry.h" -#include "system_ability_definition.h" - -namespace OHOS { -int TestClient::ConnectService() -{ - auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (saMgr == nullptr) { - ZLOGE(LABEL, "get registry fail"); - return -1; - } +-d后的dir为目标输出目录,以输出文件夹名为IIdlTestServiceTs为例,在idl可执行文件所在目录下执行`idl -gen-ts -d IIdlTestServiceTs -c IIdlTestServiceTs/IIdlTestService.idl`,将会在执行环境的dir目录(即IIdlTestServiceTs目录)中生成接口文件、Stub文件、Proxy文件。 - sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); - if (object != nullptr) { - ZLOGE(LABEL, "Got test Service object"); - testService_ = (new (std::nothrow) IdlTestServiceProxy(object)); - } +> **注意**:生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。 - if (testService_ == nullptr) { - ZLOGE(LABEL, "Could not find Test Service!"); - return -1; - } - - return 0; -} +以名为`IIdlTestService.idl`的.idl文件、目标输出文件夹为IIdlTestServiceTs为例,其目录结构应类似于: -void TestClient::StartIntTransaction() -{ - if (testService_ != nullptr) { - ZLOGE(LABEL, "StartIntTransaction"); - [[maybe_unused]] int result = 0; - testService_->TestIntTransaction(1234, result); // 1234 : test number - ZLOGE(LABEL, "Rec result from server %{public}d.", result); - } -} - -void TestClient::StartStringTransaction() -{ - if (testService_ != nullptr) { - ZLOGI(LABEL, "StartIntTransaction"); - testService_->TestStringTransaction("IDL Test"); - } -} -} // namespace OHOS ``` - -### TS开发步骤 - -#### 创建.idl文件 - - 开发者可以使用TS编程语言构建.idl文件。.idl示例如下: - -```ts - interface OHOS.IIdlTestService { - int TestIntTransaction([in] int data); - void TestStringTransaction([in] String data); - } +├── IIdlTestServiceTs # idl代码输出文件夹 +│ ├── i_idl_test_service.ts # 生成文件 +│ ├── idl_test_service_proxy.ts # 生成文件 +│ ├── idl_test_service_stub.ts # 生成文件 +│ └── IIdlTestService.idl # 构造的.idl文件 +└── idl.exe # idl的可执行文件 ``` -使用者通过执行命令 “./idl -c IIdlTestService.idl -gen-ts -d /data/ts/” (-d为输出目录)在执行环境的/data/ts/目录中生成接口文件、Stub文件、Proxy文件。生成的接口类文件名称和.idl文件名称保持一致,区别在于其使用.ts扩展名。例如,IIdlTestService.idl 生成的文件名是 i_idl_test_service.ts、idl_test_service_proxy.ts、idl_test_service_stub.ts。 - #### 服务端公开接口 OpenHarmony IDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法。 @@ -356,8 +211,8 @@ export default class IdlTestServiceStub extends rpc.RemoteObject implements IIdl super(des); } - onRemoteRequest(code: number, data, reply, option): boolean { - console.log("onRemoteRequest called, code = " + code); + async onRemoteRequestEx(code: number, data, reply, option): Promise { + console.log("onRemoteRequestEx called, code = " + code); switch(code) { case IdlTestServiceStub.COMMAND_TEST_INT_TRANSACTION: { let _data = data.readInt(); @@ -529,137 +384,3 @@ export default class MySequenceable { private str; } ``` - -## C++与TS互通开发步骤 - -### TS Proxy与C++ Stub开发步骤 - -#### C++端提供服务对象 - -1. 如上所述C++开发步骤,开发者使用C++编程语言构建.idl文件,通过命令生成接口、Stub文件、Proxy文件。 - -2. 开发者创建服务对象,并继承C++ Stub文件中定义的接口类并实现其中的方法,例如: - - ```cpp - class IdlTestServiceImpl : public IdlTestServiceStub { - public: - IdlTestServiceImpl() = default; - virtual ~IdlTestServiceImpl() = default; - - ErrCode TestIntTransaction(int _data, int& result) override - { - result = 256; - return ERR_OK; - } - - ErrCode TestStringTransaction(const std::string& _data) override - { - return ERR_OK; - } - }; - ``` - -#### C++端提供napi接口 - -C++需要通过napi的方式,把C++服务对象提供给TS端,例如:C++端提供一个GetNativeObject方法,方法里创建IdlTestServiceImpl实例,通过NAPI_ohos_rpc_CreateJsRemoteObject方法,创建出一个JS远程对象供TS应用使用,如下: - -```cpp -NativeValue* GetNativeObject(NativeEngine& engine, NativeCallbackInfo& info) -{ - sptr impl = new IdlTestServiceImpl(); - napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(reinterpret_cast(&engine), impl); - NativeValue* nativeRemoteObject = reinterpret_cast(napiRemoteObject); - return nativeRemoteObject; -} -``` - -#### TS端提供Proxy对象 - -如上所述TS开发步骤,开发者使用TS编程语言构建.idl文件,通过命令生成接口、Stub文件、Proxy文件。Proxy文件例如: - -```ts -import {testIntTransactionCallback} from "./i_idl_test_service"; -import {testStringTransactionCallback} from "./i_idl_test_service"; -import IIdlTestService from "./i_idl_test_service"; -import rpc from "@ohos.rpc"; - -export default class IdlTestServiceProxy implements IIdlTestService { - constructor(proxy) { - this.proxy = proxy; - } - - testIntTransaction(data: number, callback: testIntTransactionCallback): void - { - let _option = new rpc.MessageOption(); - let _data = new rpc.MessageParcel(); - let _reply = new rpc.MessageParcel(); - _data.writeInt(data); - this.proxy.sendRequest(IdlTestServiceProxy.COMMAND_TEST_INT_TRANSACTION, _data, _reply, _option).then(function(result) { - if (result.errCode == 0) { - let _errCode = result.reply.readInt(); - if (_errCode != 0) { - let _returnValue = undefined; - callback(_errCode, _returnValue); - return; - } - let _returnValue = result.reply.readInt(); - callback(_errCode, _returnValue); - } else { - console.log('sendRequest failed, errCode: ' + result.errCode); - } - }) - } - - testStringTransaction(data: string, callback: testStringTransactionCallback): void - { - let _option = new rpc.MessageOption(); - let _data = new rpc.MessageParcel(); - let _reply = new rpc.MessageParcel(); - _data.writeString(data); - this.proxy.sendRequest(IdlTestServiceProxy.COMMAND_TEST_STRING_TRANSACTION, _data, _reply, _option).then(function(result) { - if (result.errCode == 0) { - let _errCode = result.reply.readInt(); - callback(_errCode); - } else { - console.log('sendRequest failed, errCode: ' + result.errCode); - } - }) - } - - static readonly COMMAND_TEST_INT_TRANSACTION = 1; - static readonly COMMAND_TEST_STRING_TRANSACTION = 2; - private proxy -} -``` - -#### TS与C++实现互通 - -1. TS应用调用napi接口获取C++服务的远程对象 -2. 构建TS Proxy对象,并把C++服务的远程对象传递给它 -3. 此时开发者通过TS Proxy对象调用.idl声明的方法,实现TS Proxy与C++ Stub的互通,示例如下: - -```ts -import IdlTestServiceProxy from './idl_test_service_proxy' -import nativeMgr from 'nativeManager'; - -function testIntTransactionCallback(errCode: number, returnValue: number) -{ - console.log('errCode: ' + errCode + ' returnValue: ' + returnValue); -} - -function testStringTransactionCallback(errCode: number) -{ - console.log('errCode: ' + errCode); -} - -function jsProxyTriggerCppStub() -{ - let nativeObj = nativeMgr.GetNativeObject(); - let tsProxy = new IdlTestServiceProxy(nativeObj); - // invoke testIntTransaction - tsProxy.testIntTransaction(10, testIntTransactionCallback); - - // invoke testStringTransaction - tsProxy.testStringTransaction('test', testIntTransactionCallback); -} -```