diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index f487ec8a1225f3956c9d5fa7ec48d2bfa9ee867f..03e549542931ea02913eece6c21bcbcaadd7aa27 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -28,5 +28,6 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/wantagent:aniwantagent", "${ability_runtime_path}/frameworks/ets/ani/application:application_ani", + "${ability_runtime_path}/frameworks/ets/ani/event_hub:event_hub_ani_kit", ] } \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/BUILD.gn b/frameworks/ets/ani/event_hub/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c5d91807f0fcc9e2c1252e979d5970735b6901c1 --- /dev/null +++ b/frameworks/ets/ani/event_hub/BUILD.gn @@ -0,0 +1,84 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("event_hub_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_path}/frameworks/ets/ani/enum_convert", + "${ability_runtime_path}/interfaces/kits/native/ability/native", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/ability_delegator/include", + "${ability_runtime_services_path}/common/include", + ] + configs = [] + + public_configs = [] + + sources = [ + "./src/ts_hybridgrep.cpp", + "./src/ets_hybridgrep.cpp", + "./src/event_hub.cpp", + ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/ability_manager:ability_start_options", + "${ability_runtime_innerkits_path}/error_utils:ability_runtime_error_util", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${ability_runtime_native_path}/ability/native:abilitykit_native", + "${ability_runtime_native_path}/ability/native:ability_business_error", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:appkit_delegator", + "${ability_runtime_native_path}/appkit:delegator_mgmt", + ] + + external_deps = [ + "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "eventhandler:libeventhandler", + "hilog:libhilog", + "init:libbegetutil", + "json:nlohmann_json_static", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", + ] + + public_external_deps = [ "ability_base:configuration" ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/include/ets_hybridgref.h b/frameworks/ets/ani/event_hub/include/ets_hybridgref.h new file mode 100644 index 0000000000000000000000000000000000000000..def4f06a39b765311ed8bd8dcaf0a62e74d88849 --- /dev/null +++ b/frameworks/ets/ani/event_hub/include/ets_hybridgref.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETS_HYBRIDGREF_H +#define ETS_HYBRIDGREF_H + +#include "ts_hybridgref.h" +#include "sts_runtime.h" + +namespace OHOS { +namespace AbilityRuntime { + +class HybridGrefPrimitiveEtsToTs { +public: + static bool RegisterNativeGetRef(napi_env env); + static bool RegisterNativeSaveRef(ani_env* env); +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // ETS_HYBRIDGREF_H \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/include/event_hub.h b/frameworks/ets/ani/event_hub/include/event_hub.h new file mode 100644 index 0000000000000000000000000000000000000000..9760dc40a79cd3c9e4705c6ac80b4aacd5420610 --- /dev/null +++ b/frameworks/ets/ani/event_hub/include/event_hub.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef EVENT_HUB_H +#define EVENT_HUB_H + +#include "ets_hybridgref.h" +#include "ts_hybridgref.h" + +namespace OHOS { +namespace AbilityRuntime { + +class EventHub { +public: + static void InitAni(ani_env* env); + static napi_value InitEventHubNapi(napi_env env, napi_value exportObj); +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // EVENT_HUB_H \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/include/ts_hybridgref.h b/frameworks/ets/ani/event_hub/include/ts_hybridgref.h new file mode 100644 index 0000000000000000000000000000000000000000..3ab3b794fca4c6af1971a68700a72eed238812c6 --- /dev/null +++ b/frameworks/ets/ani/event_hub/include/ts_hybridgref.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TS_HYBRIDGREF_H +#define TS_HYBRIDGREF_H + +#include +#include "napi/native_api.h" +#include "native_engine/native_engine.h" +#include "sts_runtime.h" + +namespace OHOS { +namespace AbilityRuntime { +using hybridgref = void*; + +class NativeGrefTsToEts { +public: + static bool RegisterNativeSaveRef(napi_env env); + static bool RegisterETSGetter(ani_env* env); +}; + +} // namespace AbilityRuntime +} // namespace OHOS +#endif // TS_HYBRIDGREF_H \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/src/ets_hybridgref.cpp b/frameworks/ets/ani/event_hub/src/ets_hybridgref.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b4adabaa798692b89704011c7f652f6eda293fe --- /dev/null +++ b/frameworks/ets/ani/event_hub/src/ets_hybridgref.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ets_hybridgref.h" + +#include "hilog_tag_wrapper.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include + +namespace OHOS { +namespace AbilityRuntime { + +static __hybridgref* g_ref = nullptr; +static napi_value NativeGetRef(napi_env env, [[maybe_unused]] napi_callback_info info) +{ + napi_value result {}; + if (!hybridgref_get_napi_value(env, g_ref, &result)) { + napi_get_undefined(env, &result); + } + return result; +} + +static void NativeSaveHybridGref(ani_env *env, ani_object ref) +{ + if (!hybridgref_create_from_ani(env, static_cast(ref), &g_ref)) { + return; + } +} + +bool HybridGrefPrimitiveEtsToTs::RegisterNativeGetRef(napi_env env) +{ + napi_value global; + if (napi_get_global(env, &global) != napi_ok) { + return false; + } + napi_value fn; + if (napi_create_function(env, "nativeGetRef", NAPI_AUTO_LENGTH, NativeGetRef, nullptr, &fn) != napi_ok) { + return false; + } + + if (napi_set_named_property(env, global, "nativeGetRef", fn) != napi_ok) { + return false; + } + + return true; +} + +bool HybridGrefPrimitiveEtsToTs::RegisterNativeSaveRef(ani_env *env) +{ + ani_module etsMod {}; + auto status = env->FindModule("Lets_functions;", &etsMod); + if (status != ANI_OK) { + return false; + } + std::array methods = { + ani_native_function {"saveHybridGref", nullptr, reinterpret_cast(NativeSaveHybridGref)}, + }; + status = env->Module_BindNativeFunctions(etsMod, methods.data(), methods.size()); + return status == ANI_OK; +} + +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/src/event_hub.cpp b/frameworks/ets/ani/event_hub/src/event_hub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1b9140506c8323710b6dbb58e228aee4460557b --- /dev/null +++ b/frameworks/ets/ani/event_hub/src/event_hub.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "event_hub.h" + +#include "ts_hybridgref.h" +#include "ets_hybridgref.h" +#include +#include "hilog_tag_wrapper.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" + +namespace OHOS { +namespace AbilityRuntime { + +static std::atomic g_initialized(false); + +void EventHub::InitAni(ani_env *aniEnv) { + if (g_initialized.exchange(true)) { + return; + } + + if (!aniEnv) { + TAG_LOGE(AAFwkTag::APPKIT, "Invalid ani_env in InitAni"); + return; + } + + bool success = NativeGrefTsToEts::RegisterETSGetter(aniEnv) && + HybridGrefPrimitiveEtsToTs::RegisterNativeSaveRef(aniEnv); + + TAG_LOGI(AAFwkTag::APPKIT, "EventHub ANI initialization %s", + success ? "succeeded" : "failed"); +} + +napi_value EventHub::InitEventHubNapi(napi_env env, napi_value exportObj) { + if (!env) { + TAG_LOGE(AAFwkTag::APPKIT, "Invalid napi_env in InitEventHubNapi"); + return nullptr; + } + + bool success = NativeGrefTsToEts::RegisterNativeSaveRef(env) && + HybridGrefPrimitiveEtsToTs::RegisterNativeGetRef(env); + + TAG_LOGI(AAFwkTag::APPKIT, "EventHub NAPI initialization %s", + success ? "succeeded" : "failed"); + + return exportObj; +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::APPKIT, "in EventHub ETS.ANI_Constructor"); + if (vm == nullptr || result == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null vm or result"); + return ANI_INVALID_ARGS; + } + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "GetEnv failed, status: %{public}d", status); + return ANI_NOT_FOUND; + } + InitAni(env); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::APPKIT, "EventHub.ANI_Constructor finished"); + return ANI_OK; +} +} + +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/event_hub/src/ts_hybridgref.cpp b/frameworks/ets/ani/event_hub/src/ts_hybridgref.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc34f01b2bae0aeb5b7d64f17eb4a89a1a292c4e --- /dev/null +++ b/frameworks/ets/ani/event_hub/src/ts_hybridgref.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ts_hybridgref.h" + +#include "hilog_tag_wrapper.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include + +namespace OHOS { +namespace AbilityRuntime { + +static __hybridgref* g_jsToEtsEventHubOnRef = nullptr; +static __hybridgref* g_jsToEtsEventHubOffRef = nullptr; +static __hybridgref* g_jsToEtsEventHubEmitRef = nullptr; + +static napi_value NativeSaveEventHubOnRef(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1]; // NOLINT(modernize-avoid-c-arrays) + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + + if (argc < 1) { + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; + } + + if (g_jsToEtsEventHubOnRef != nullptr) { + hybridgref_delete_from_napi(env, g_jsToEtsEventHubOnRef); + g_jsToEtsEventHubOnRef = nullptr; + } + + bool ok = hybridgref_create_from_napi(env, argv[0], &g_jsToEtsEventHubOnRef); + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +static napi_value NativeSaveEventHubOffRef(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1]; // NOLINT(modernize-avoid-c-arrays) + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + + if (argc < 1) { + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; + } + + if (g_jsToEtsEventHubOffRef != nullptr) { + hybridgref_delete_from_napi(env, g_jsToEtsEventHubOffRef); + g_jsToEtsEventHubOffRef = nullptr; + } + + bool ok = hybridgref_create_from_napi(env, argv[0], &g_jsToEtsEventHubOffRef); + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +static napi_value NativeSaveEventHubEmitRef(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1]; // NOLINT(modernize-avoid-c-arrays) + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + + if (argc < 1) { + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; + } + + if (g_jsToEtsEventHubEmitRef != nullptr) { + hybridgref_delete_from_napi(env, g_jsToEtsEventHubEmitRef); + g_jsToEtsEventHubEmitRef = nullptr; + } + + bool ok = hybridgref_create_from_napi(env, argv[0], &g_jsToEtsEventHubEmitRef); + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +static ani_object NativeGetEventHubOnRef(ani_env *env) +{ + ani_object result {}; + hybridgref_get_esvalue(env, g_jsToEtsEventHubOnRef, &result); + return result; +} + +static ani_object NativeGetEventHubOffRef(ani_env *env) +{ + ani_object result {}; + hybridgref_get_esvalue(env, g_jsToEtsEventHubOffRef, &result); + return result; +} + +static ani_object NativeGetEventHubEmitRef(ani_env *env) +{ + ani_object result {}; + hybridgref_get_esvalue(env, g_jsToEtsEventHubEmitRef, &result); + return result; +} + +bool NativeGrefTsToEts::RegisterNativeSaveRef(napi_env env) +{ + napi_value global; + if (napi_get_global(env, &global) != napi_ok) { + return false; + } + + napi_value nativeSaveEventHubOnFn; + if (napi_create_function(env, "nativeSaveEventHubOnRef", NAPI_AUTO_LENGTH, NativeSaveEventHubOnRef, nullptr, &nativeSaveEventHubOnFn) != napi_ok) { + return false; + } + if (napi_set_named_property(env, global, "nativeSaveEventHubOnRef", nativeSaveEventHubOnFn) != napi_ok) { + return false; + } + + napi_value nativeSaveEventHubOffFn; + if (napi_create_function(env, "nativeSaveEventHubOffRef", NAPI_AUTO_LENGTH, NativeSaveEventHubOffRef, nullptr, &nativeSaveEventHubOffFn) != napi_ok) { + return false; + } + if (napi_set_named_property(env, global, "nativeSaveEventHubOffRef", nativeSaveEventHubOffFn) != napi_ok) { + return false; + } + + napi_value nativeSaveEventHubEmitFn; + if (napi_create_function(env, "nativeSaveEventHubEmitRef", NAPI_AUTO_LENGTH, NativeSaveEventHubEmitRef, nullptr, &nativeSaveEventHubEmitFn) != napi_ok) { + return false; + } + if (napi_set_named_property(env, global, "nativeSaveEventHubEmitRef", nativeSaveEventHubEmitFn) != napi_ok) { + return false; + } + + return true; +} + +bool NativeGrefTsToEts::RegisterETSGetter(ani_env *env) +{ + ani_module mod {}; + if (env->FindModule("Lets_functions;", &mod) != ANI_OK) { + return false; + } + + std::array methods = { + ani_native_function {"nativeGetEventHubOnRef", nullptr, reinterpret_cast(NativeGetEventHubOnRef)}, + ani_native_function {"nativeGetEventHubOffRef", nullptr, reinterpret_cast(NativeGetEventHubOffRef)}, + ani_native_function {"nativeGetEventHubEmitRef", nullptr, reinterpret_cast(NativeGetEventHubEmitRef)}, + }; + return env->Module_BindNativeFunctions(mod, methods.data(), methods.size()) == ANI_OK; +} + +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ets/application/EventHub.ets b/frameworks/ets/ets/application/EventHub.ets index e207537e5099779524cb7b09aaa303eefaea8b5a..feede55bfed0801ea47db2900891895360a0da0e 100644 --- a/frameworks/ets/ets/application/EventHub.ets +++ b/frameworks/ets/ets/application/EventHub.ets @@ -13,180 +13,132 @@ * limitations under the License. */ -export default class EventHub { - private eventMap: Map> = new Map>(); - - private getCloneArray(event: string): Array { - if (this.eventMap.get(event)) { - const array: Array = this.eventMap.get(event) as Array; - const cloneArray = deepcopy>(array) as Array; - return cloneArray; - } - return new Array(); - } +type refType = Object | ESObject; +type RegisterEmitFunction = (event: string, ...args: FixedArray) => void; + +interface EventHubRegistration { + registerOn: (event: string, callback: Function) => void; + registerOff: (event: string, callback?: Function) => void; + registerEmit: RegisterEmitFunction; +} + +type refType = Object | ESObject; +type RegisterEmitFunction = (event: string, ...args: FixedArray) => void; + +interface EventHubRegistration { + registerOn: (event: string, callback: Function) => void; + registerOff: (event: string, callback?: Function) => void; + registerEmit: RegisterEmitFunction; +} - on(event: string, callback: Object) { - if (!this.eventMap.get(event)) { - this.eventMap.set(event, new Array()); - } - let array: Array = this.eventMap.get(event) as Array; - if (array.indexOf(callback) === -1) { - array.push(callback); - } - } - - off(event: string, callback: Object) { - if (this.eventMap.get(event)) { - let cbArray: Array = this.eventMap.get(event) as Array; - let index: number = cbArray.indexOf(callback); - if (index > -1) { - for (; index + 1 < cbArray.length; index++) { - cbArray[index] = cbArray[index + 1]; - } - cbArray.pop(); - } - } - } - - off(event: string) { - if (this.eventMap.get(event)) { - this.eventMap.delete(event); - } - } +export default class EventHub { - emit(event:string) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - let f = cloneArray[i] as () => void; - f(); - } - } + native nativeGetEventHubOnRef(): ESObject; + native nativeGetEventHubOffRef(): ESObject; + native nativeGetEventHubEmitRef(): ESObject; - emit(event:string, p1: P1) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - let f = cloneArray[i] as (p1: P1) => void; - f(p1); - } - } + native saveEventHubOnHybridGref(ref: refType): void; + native saveEventHubOffHybridGref(ref: refType): void; + native saveEventHubEmitHybridGref(ref: refType): void; - emit(event: string, p1: P1, p2: P2) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2) => void; - f(p1, p2); - } - } + private eventMap: Map = new Map(); - emit(event: string, p1: P1, p2: P2, p3: P3) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3) => void; - f(p1, p2, p3); - } - } - - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4) => void; - f(p1, p2, p3, p4); - } - } + constructor() { + this.saveEventHubOnHybridGref({ + registerOn: (event: string, callback: Function): void => { + this.on(event, callback, true); + } + } as EventHubRegistration); + this.saveEventHubOffHybridGref({ + registerOff: (event: string, callback?: Function): void => { + this.off(event, callback, true); + } + } as EventHubRegistration); - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => void; - f(p1, p2, p3, p4, p5); + const emitHandler: RegisterEmitFunction = (event: string, ...args: FixedArray): void => { + this.emit(event, ...args); } - } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) => void; - f(p1, p2, p3, p4, p5, p6); - } + this.saveEventHubEmitHybridGref({ registerEmit: emitHandler } as EventHubRegistration); } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) => void; - f(p1, p2, p3, p4, p5, p6, p7); + private registerOnCallback(event: string, callback: Function): void { + if (!this.eventMap.has(event)) { + this.eventMap.set(event, []); } - } - - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8); + + const callbacks = this.eventMap.get(event)!; + if (!callbacks.includes(callback)) { + callbacks.push(callback); } } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9); - } - } + on(event: string, callback: Function, fromNative: boolean = false): void { + this.registerOnCallback(event, callback); - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + if (!fromNative) { + let nativeObj = this.nativeGetEventHubOnRef(); + if (nativeObj) { + nativeObj.invokeMethod(event, callback); + } } } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + private registerOffCallback(event: string, callback?: Function): void { + if (!this.eventMap.has(event)) { + return; } - } - - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + + if (!callback) { + this.eventMap.delete(event); + } else { + const callbacks = this.eventMap.get(event)!; + const index = callbacks.indexOf(callback); + if (index > -1) { + callbacks.splice(index, 1); + } + + if (callbacks.length === 0) { + this.eventMap.delete(event); + } } } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); - } - } + off(event: string, callback?: Function, fromNative: boolean = false): void { + this.registerOffCallback(event, callback); - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + if (!fromNative) { + const nativeObj = this.nativeGetEventHubOffRef(); + if (nativeObj) { + if (callback) { + nativeObj.invokeMethod(event, callback); + } else { + nativeObj.invokeMethod(event); + } + } } } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + private registerEmitCallback(event: string, ...args: FixedArray): void { + if (!this.eventMap.has(event)) { + return; } + + const callbacks = [...this.eventMap.get(event)!]; + callbacks.forEach(callback => { + try { + callback.unsafeCall(...args); + } catch (e) { + console.error(`Error triggering event '${event}':`, e); + } + }); } - emit(event: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16) { - const cloneArray: Array = this.getCloneArray(event); - for (let i = 0; i < cloneArray.length; ++i) { - const f = cloneArray[i] as (p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16) => void; - f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); + emit(event: string, ...args: FixedArray): void { + this.registerEmitCallback(event, ...args); + const nativeObj = this.nativeGetEventHubEmitRef(); + if (nativeObj) { + nativeObj.invokeMethod(event, ...args); } } } \ No newline at end of file diff --git a/frameworks/js/napi/app/context/BUILD.gn b/frameworks/js/napi/app/context/BUILD.gn index 46d7a1c625baa50ee4713c87fca62b848aa3d974..bc75c83ab5e9d411552711b0711ab7e6a5be1c97 100644 --- a/frameworks/js/napi/app/context/BUILD.gn +++ b/frameworks/js/napi/app/context/BUILD.gn @@ -13,6 +13,7 @@ import("//build/config/components/ets_frontend/es2abc_config.gni") import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") es2abc_gen_abc("gen_context_abc") { src_js = rebase_path("context.js") @@ -36,7 +37,10 @@ gen_js_obj("context_abc") { ohos_shared_library("context_napi") { sources = [ "context_module.cpp" ] + include_dirs = [ "${ability_runtime_path}/frameworks/ets/ani/event_hub/include" ] + deps = [ + "${ability_runtime_path}/frameworks/ets/ani/event_hub:event_hub_ani_kit", ":context_abc", ":context_js", ] diff --git a/frameworks/js/napi/app/context/context.js b/frameworks/js/napi/app/context/context.js index ed65a7c7aeca993e2832db6948e7bae4a9e96c89..951ff9f9dad07fe087256b3e35931070c56a83af 100644 --- a/frameworks/js/napi/app/context/context.js +++ b/frameworks/js/napi/app/context/context.js @@ -13,12 +13,60 @@ * limitations under the License. */ +// eventHub.js +let etsOnHandler = null; +let etsOffHandler = null; +let etsEmitHandler = null; + +globalThis.nativeSaveEventHubOnRef = (handler) => { + etsOnHandler = handler; +}; + +globalThis.nativeSaveEventHubOffRef = (handler) => { + etsOffHandler = handler; +} + +globalThis.nativeSaveEventHubEmitRef = (handler) => { + etsEmitHandler = handler; +} + class EventHub { constructor() { this.eventMap = {}; + this.initNativeCommunication(); } - on(event, callback) { + initNativeCommunication() { + const onHandler = { + handleOn: (event, callback) => { + this.on(event, callback, true) + } + }; + + const offHandler = { + handleOff: (event, callback) => { + this.off(event, callback, true) + } + }; + + const emitHandler = { + handleEmit: (event, callback) => { + this.emit(event, ...args); + } + } + + if (globalThis.nativeSaveEventHubOnRef) { + globalThis.nativeSaveEventHubOnRef(onHandler); + } + if (globalThis.nativeSaveEventHubOffRef) { + globalThis.nativeSaveEventHubOffRef(offHandler); + } + if (globalThis.nativeSaveEventHubEmitRef) { + globalThis.nativeSaveEventHubEmitRef(emitHandler); + } + } + + on(event, callback, fromNative = false) { if ((typeof (event) !== 'string') || (typeof (callback) !== 'function')) { return; } @@ -28,6 +76,14 @@ class EventHub { if (this.eventMap[event].indexOf(callback) === -1) { this.eventMap[event].push(callback); } + + if (!fromNative && etsOnHandler) { + try { + etsOnHandler.handleOn(event, callback); + } catch (e) { + console.error(`Failed to register event '${event}' with Native: `, e); + } + } } off(event, callback) { @@ -48,6 +104,18 @@ class EventHub { delete this.eventMap[event]; } } + + if (!fromNative && etsOffHandler) { + try { + if (callback) { + etsOffHandler.handleOff(event, callback); + } else { + etsOffHandler.handleOff(event); + } + } catch (e) { + console.error(`Failed to unregister event '${event}' with Native:`, e); + } + } } emit(event, ...args) { @@ -61,6 +129,18 @@ class EventHub { cloneArray[i].apply(this, args); } } + + if (etsEmitHandler) { + try { + etsEmitHandler.handleEmit(event, ...args); + } catch (e) { + console.error(`Failed to emit event '${event}' to Native:`, e); + } + } + } + + dispose() { + this.eventMap = {}; } } diff --git a/frameworks/js/napi/app/context/context_module.cpp b/frameworks/js/napi/app/context/context_module.cpp index 0bb370f1f31b5a5267854c8bbe78ae7fa8bc0bab..2d0b1847df99d3718976e261b752bc1f7ef36d13 100644 --- a/frameworks/js/napi/app/context/context_module.cpp +++ b/frameworks/js/napi/app/context/context_module.cpp @@ -14,6 +14,7 @@ */ #include "native_engine/native_engine.h" +#include "event_hub.h" extern const char _binary_context_js_start[]; extern const char _binary_context_js_end[]; @@ -23,6 +24,7 @@ extern const char _binary_context_abc_end[]; static napi_module _module = { .nm_version = 0, .nm_filename = "application/libcontext_napi.so/context.js", + .nm_register_func = OHOS:AbilityRuntim::InitEventHubNapi, .nm_modname = "application.Context", };