diff --git a/arkoala-arkts/arkui/src/CallbacksChecker.ts b/arkoala-arkts/arkui/src/CallbacksChecker.ts index 31d5cead010f9ab4cb3b713fe37ccca77999cb30..be9e489d66ce5e1204b91fe69df8e62c6676ec61 100644 --- a/arkoala-arkts/arkui/src/CallbacksChecker.ts +++ b/arkoala-arkts/arkui/src/CallbacksChecker.ts @@ -17,11 +17,14 @@ import { KBuffer } from "@koalaui/interop" import { Deserializer } from "./generated/peers/Deserializer"; import { deserializeAndCallCallback } from "./generated/peers/CallbackDeserializeCall" import { ResourceHolder, InteropNativeModule } from "@koalaui/interop" +import { destroyUiDetachedRoot } from "./Application" +import { PeerNode } from "./PeerNode"; enum CallbackEventKind { Event_CallCallback = 0, Event_HoldManagedResource = 1, Event_ReleaseManagedResource = 2, + Event_ReleaseComponent = 3, } const bufferSize = 4096 @@ -49,6 +52,16 @@ export function checkArkoalaCallbacks() { ResourceHolder.instance().release(resourceId) break; } + case CallbackEventKind.Event_ReleaseComponent: { + const nodeId = deserializer.readPointer(); + const peer = PeerNode.findPeerByNativeId(nodeId) + if (peer !== undefined) { + destroyUiDetachedRoot(peer) + } else { + InteropNativeModule._NativeLog("ERROR: can not find PeerNode for native id " + nodeId) + } + break; + } default: throw new Error(`Unknown callback event kind ${eventKind}`) } } diff --git a/arkoala-arkts/framework/native/src/generated/library.cc b/arkoala-arkts/framework/native/src/generated/library.cc index 8bb21b9457d4bf649779655a142bce3bb68cb7c9..31380962b040efce67faa038643688284deae1da 100644 --- a/arkoala-arkts/framework/native/src/generated/library.cc +++ b/arkoala-arkts/framework/native/src/generated/library.cc @@ -18,6 +18,8 @@ #include "interop-types.h" #include "dynamic-loader.h" #include "interop-logging.h" +#include "arkoala_api_generated.h" +#include "callback-resource.h" #ifndef GENERATED_FOUNDATION_ACE_FRAMEWORKS_CORE_INTERFACES_ANY_API_H #define GENERATED_FOUNDATION_ACE_FRAMEWORKS_CORE_INTERFACES_ANY_API_H @@ -133,6 +135,10 @@ const OH_AnyAPI* GetAnyImpl(int kind, int version, std::string* result) { if (service) { if (logger) service->setLogger(reinterpret_cast(logger)); } + auto extended = (const GENERATED_ArkUIExtendedNodeAPI*)(*getAPI)(GENERATED_EXTENDED, GENERATED_ARKUI_EXTENDED_NODE_API_VERSION); + if (extended) { + extended->setCustomNodeDestroyCallback((void(*)(Ark_NodeHandle))releaseComponent); + } impl = (*getAPI)(kind, version); if (!impl) { diff --git a/arkoala/arkui/src/peer_events_checker.ts b/arkoala/arkui/src/peer_events_checker.ts index ff4c37a200ce240d02037c00b7d60afd1f014af1..5f24147be525d7f49bb59e789e1827712a8b0bac 100644 --- a/arkoala/arkui/src/peer_events_checker.ts +++ b/arkoala/arkui/src/peer_events_checker.ts @@ -2,11 +2,14 @@ import { InteropNativeModule, ResourceHolder } from "@koalaui/interop" import { setCustomEventsChecker } from "@koalaui/arkoala" import { Deserializer } from "./generated/peers/Deserializer" import { deserializeAndCallCallback } from "./generated/peers/CallbackDeserializeCall" +import { PeerNode } from "@koalaui/arkoala" +import { destroyUiDetachedRoot } from "@koalaui/arkoala" enum CallbackEventKind { Event_CallCallback = 0, Event_HoldManagedResource = 1, Event_ReleaseManagedResource = 2, + Event_ReleaseComponent = 3, } const bufferSize = 4096 @@ -34,6 +37,16 @@ export function checkArkoalaCallbacks() { ResourceHolder.instance().release(resourceId) break; } + case CallbackEventKind.Event_ReleaseComponent: { + const nodeId = deserializer.readPointer(); + const peer = PeerNode.findPeerByNativeId(nodeId as number) + if (peer !== undefined) { + destroyUiDetachedRoot(peer) + } else { + InteropNativeModule._NativeLog("ERROR: can not find PeerNode for native id " + nodeId) + } + break; + } default: throw new Error(`Unknown callback event kind ${eventKind}`) } } diff --git a/interop/src/cpp/callback-resource.cc b/interop/src/cpp/callback-resource.cc index acbe9cd23990ff07d6e2a0ef6f83175701a345ea..197b87a9498e0482a22d0acca9a9daeb4a4b1064 100644 --- a/interop/src/cpp/callback-resource.cc +++ b/interop/src/cpp/callback-resource.cc @@ -26,6 +26,7 @@ static bool needReleaseFront = false; static std::deque callbackEventsQueue; static std::deque callbackCallSubqueue; static std::deque callbackResourceSubqueue; +static std::deque componentSubqueue; void enqueueCallback(const CallbackBuffer* event) { callbackEventsQueue.push_back(Event_CallCallback); @@ -42,6 +43,11 @@ void releaseManagedCallbackResource(InteropInt32 resourceId) { callbackResourceSubqueue.push_back(resourceId); } +void releaseComponent(InteropNativePointer nodeId) { + callbackEventsQueue.push_back(Event_ReleaseComponent); + componentSubqueue.push_back(nodeId); +} + KInt impl_CheckCallbackEvent(KSerializerBuffer buffer, KInt size) { KByte* result = (KByte*)buffer; if (needReleaseFront) @@ -56,6 +62,9 @@ KInt impl_CheckCallbackEvent(KSerializerBuffer buffer, KInt size) { case Event_ReleaseManagedResource: callbackResourceSubqueue.pop_front(); break; + case Event_ReleaseComponent: + componentSubqueue.pop_front(); + break; default: INTEROP_FATAL("Unknown event kind"); } @@ -91,6 +100,15 @@ KInt impl_CheckCallbackEvent(KSerializerBuffer buffer, KInt size) { #endif break; } + case Event_ReleaseComponent: { + const InteropNativePointer nodeId = componentSubqueue.front(); + #ifdef __STDC_LIB_EXT1__ + memcpy_s(result + 4, size, &frontEventKind, 4); + #else + memcpy(result + 4, &nodeId, 8); + #endif + break; + } default: INTEROP_FATAL("Unknown event kind"); } diff --git a/interop/src/cpp/callback-resource.h b/interop/src/cpp/callback-resource.h index c7a742a052dad85cd6cbd148d73fb0a63afd50a0..478c534994cc1061c98c564ce74826492dbb3b9d 100644 --- a/interop/src/cpp/callback-resource.h +++ b/interop/src/cpp/callback-resource.h @@ -51,10 +51,13 @@ enum CallbackEventKind { Event_CallCallback = 0, Event_HoldManagedResource = 1, Event_ReleaseManagedResource = 2, + Event_ReleaseComponent = 3, }; extern "C" DLL_EXPORT void enqueueCallback(const CallbackBuffer* event); extern "C" DLL_EXPORT void holdManagedCallbackResource(InteropInt32 resourceId); extern "C" DLL_EXPORT void releaseManagedCallbackResource(InteropInt32 resourceId); +// TODO must be removed later. CustomBuilder must return not pointer to component but pointer + CallbackResource, that allows to control component lifecycle +extern "C" DLL_EXPORT void releaseComponent(InteropNativePointer nodeId); #endif