* 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 "bridge/arkts_frontend/arkts_frontend.h"
#include <ani.h>
#include <ani_signature_builder.h>
#include "ets_ani_expo.h"
#include "interfaces/inner_api/ace/constants.h"
#include "ui/base/utils/utils.h"
#include "base/utils/system_properties.h"
#include "bridge/arkts_frontend/entry/arkts_entry_loader.h"
#include "core/components_ng/pattern/stage/page_pattern.h"
#include "core/pipeline_ng/pipeline_context.h"
#include "frameworks/base/subwindow/subwindow_manager.h"
#include "bridge/arkts_frontend/ani_context_module.h"
#include "utils/ani_utils.h"
namespace OHOS::Ace {
namespace {
using namespace arkts::ani_signature;
const std::string ENTRY_SUFFIX = "/__EntryWrapper";
struct AppInfo {
const char* className;
const char* createMethodName;
const char* createMethodSig;
const char* startMethodName;
const char* startMethodSig;
const char* enterMethodName;
const char* enterMethodSig;
const char* emitEventMethodName;
const char* emitEventMethodSig;
const char* checkCallbackMethodName;
const char* checkCallbackEventMethodSig;
const char* handleMessageMethodName;
const char* handleMessageMethodSig;
const char* registerNativeModule;
const char* registerNativeModuleSig;
const char* constructorParamClassName;
const char* constructorParamCtorMethod;
const char* constructorParamSig;
};
const AppInfo KOALA_APP_INFO = {
"arkui.ArkUIEntry.Application",
"createApplication",
"C{arkui.ArkUIEntry.ApplicationConstructorParam}:C{arkui.ArkUIEntry.Application}",
"start",
"z:l",
"enter",
"iil:z",
"emitEvent",
"iiii:",
"checkCallbacks",
":",
"handleMessage",
"liC{std.core.String}:z",
"registerNativeModulePreloader",
":",
"arkui.ArkUIEntry.ApplicationConstructorParam",
"<ctor>",
"C{std.core.String}C{std.core.String}C{std.core.String}zC{std.core.String}C{arkui.UserView.UserView}"
"C{arkui.component.customComponent.EntryPoint}z:",
};
std::string GetErrorProperty(ani_env* aniEnv, ani_error aniError, const char* property)
{
TAG_LOGD(AceLogTag::ACE_SUB_WINDOW, "called");
std::string propertyValue;
ani_status status = ANI_ERROR;
ani_type errorType = nullptr;
if ((status = aniEnv->Object_GetType(aniError, &errorType)) != ANI_OK) {
TAG_LOGE(AceLogTag::ACE_SUB_WINDOW, "Object_GetType failed, status : %{public}d", status);
return propertyValue;
}
auto errorClass = static_cast<ani_class>(errorType);
ani_method getterMethod = nullptr;
if ((status = aniEnv->Class_FindMethod(errorClass, property, nullptr, &getterMethod)) != ANI_OK) {
TAG_LOGE(AceLogTag::ACE_SUB_WINDOW, "Class_FindMethod failed, status : %{public}d", status);
return propertyValue;
}
ani_ref aniRef = nullptr;
if ((status = aniEnv->Object_CallMethod_Ref(aniError, getterMethod, &aniRef)) != ANI_OK) {
TAG_LOGE(AceLogTag::ACE_SUB_WINDOW, "Object_CallMethod_Ref failed, status : %{public}d", status);
return propertyValue;
}
ani_string aniString = reinterpret_cast<ani_string>(aniRef);
ani_size sz {};
if ((status = aniEnv->String_GetUTF8Size(aniString, &sz)) != ANI_OK) {
TAG_LOGE(AceLogTag::ACE_SUB_WINDOW, "String_GetUTF8Size failed, status : %{public}d", status);
return propertyValue;
}
propertyValue.resize(sz + 1);
if ((status = aniEnv->String_GetUTF8SubString(
aniString, 0, sz, propertyValue.data(), propertyValue.size(), &sz))!= ANI_OK) {
TAG_LOGE(AceLogTag::ACE_SUB_WINDOW, "String_GetUTF8SubString failed, status : %{public}d", status);
return propertyValue;
}
propertyValue.resize(sz);
return propertyValue;
}
bool ParseRouterStateInfo(ani_env* env, ani_ref result, RouterStateInfo& state)
{
ani_double index;
ani_status status;
ani_object stateObj = static_cast<ani_object>(result);
if ((status = env->Object_GetPropertyByName_Double(stateObj, "index", &index)) != ANI_OK) {
LOGE("AceRouter failed to get index of InnerRouterState, status:%{public}d", status);
return false;
}
ani_ref nameRef;
if ((status = env->Object_GetPropertyByName_Ref(stateObj, "name", &nameRef)) != ANI_OK) {
LOGE("AceRouter failed to get name of InnerRouterState, status:%{public}d", status);
return false;
}
ani_ref pathRef;
if ((status = env->Object_GetPropertyByName_Ref(stateObj, "path", &pathRef)) != ANI_OK) {
LOGE("AceRouter failed to get path of InnerRouterState, status:%{public}d", status);
return false;
}
ani_ref paramsRef;
if ((status = env->Object_GetPropertyByName_Ref(stateObj, "params", ¶msRef)) != ANI_OK) {
LOGE("AceRouter failed to get params of InnerRouterState, status:%{public}d", status);
return false;
}
state.index = (int32_t)index;
state.name = Ani::AniUtils::ANIStringToStdString(env, static_cast<ani_string>(nameRef));
state.path = Ani::AniUtils::ANIStringToStdString(env, static_cast<ani_string>(pathRef));
state.params = Ani::AniUtils::ANIStringToStdString(env, static_cast<ani_string>(paramsRef));
return true;
}
void RunArkoalaEventLoop(ani_env* env, ani_ref app)
{
ani_boolean errorExists;
env->ExistUnhandledError(&errorExists);
ani_status status;
ani_class appClass;
if ((status = env->FindClass(KOALA_APP_INFO.className, &appClass)) != ANI_OK) {
ani_error aniError;
env->GetUnhandledError(&aniError);
env->ResetError();
std::string errorMsg = GetErrorProperty(env, aniError, Builder::BuildGetterName("message").c_str());
std::string errorName = GetErrorProperty(env, aniError, Builder::BuildGetterName("name").c_str());
std::string errorStack = GetErrorProperty(env, aniError, Builder::BuildGetterName("stack").c_str());
LOGE("[%{public}s] Cannot load main class %{public}s, status: %{public}d, \nerrorMsg: %{public}s, \nerrorName: "
"%{public}s, \nerrorStack: %{public}s",
__func__, KOALA_APP_INFO.className, status, errorMsg.c_str(), errorName.c_str(), errorStack.c_str());
ark::ets::ETSAni::HandleUncaughtException(aniError);
return;
}
ani_method enter = nullptr;
if (env->Class_FindMethod(appClass, KOALA_APP_INFO.enterMethodName, KOALA_APP_INFO.enterMethodSig, &enter) !=
ANI_OK) {
LOGE("[%{public}s] Cannot find enter method %{public}s", __func__, KOALA_APP_INFO.enterMethodName);
return;
}
ani_int arg0 = 0;
ani_int arg1 = 0;
ani_boolean result;
if (env->Object_CallMethod_Boolean(static_cast<ani_object>(app), enter, &result, arg0, arg1, nullptr) != ANI_OK) {
LOGE("[%{public}s] Call enter method failed", __func__);
return;
}
}
void FireAllArkoalaAsyncEvents(ani_env* env, ani_ref app)
{
ani_class appClass;
ANI_CALL(env, FindClass(KOALA_APP_INFO.className, &appClass), return);
ani_method checkCallbacks = nullptr;
ANI_CALL(env,
Class_FindMethod(appClass, KOALA_APP_INFO.checkCallbackMethodName, KOALA_APP_INFO.checkCallbackEventMethodSig,
&checkCallbacks),
return);
ANI_CALL(env, Object_CallMethod_Void(static_cast<ani_object>(app), checkCallbacks), return);
}
}
ArktsFrontend::ArktsFrontend(void* runtime)
{
auto* env = reinterpret_cast<ani_env*>(runtime);
if (!env) {
LOGW("ArktsFrontend AniEnv is invalid!");
return;
}
type_ = FrontendType::ARK_TS;
env->GetVM(&vm_);
pageRouterManager_ = NG::PageRouterManagerFactory::CreateManager();
}
ArktsFrontend::~ArktsFrontend()
{
auto instanceId = instanceId_;
RemoveAvailableInstanceId(instanceId);
}
ani_object LegacyLoadPage(ani_env* env)
{
do {
ani_status state;
ani_ref linkerRef;
if ((state = static_cast<ani_status>(Ani::AniUtils::GetNearestNonBootRuntimeLinker(env, linkerRef))) !=
ANI_OK) {
LOGE("Get getNearestNonBootRuntimeLinker failed, %{public}d", state);
break;
}
std::string entryPath = "entry.src.main.ets.pages.Index.ComExampleTrivialApplication";
ani_string entryClassStr;
env->String_NewUTF8(entryPath.c_str(), entryPath.length(), &entryClassStr);
ani_class entryClass = nullptr;
ani_ref entryClassRef = nullptr;
ani_class cls = nullptr;
if ((state = env->FindClass("std.core.RuntimeLinker", &cls)) != ANI_OK) {
LOGE("FindClass RuntimeLinker failed, %{public}d", state);
break;
}
ani_method loadClassMethod;
if ((state = env->Class_FindMethod(cls, "loadClass", "C{std.core.String}C{std.core.Boolean}:C{std.core.Class}",
&loadClassMethod)) != ANI_OK) {
LOGE("Class_FindMethod loadClass failed, %{public}d", state);
break;
}
ani_object isInit;
if ((state = static_cast<ani_status>(Ani::AniUtils::CreateAniBoolean(env, false, isInit))) != ANI_OK) {
LOGE("Create Boolean object failed, %{public}d", state);
break;
}
if ((state = env->Object_CallMethod_Ref(
(ani_object)linkerRef, loadClassMethod, &entryClassRef, entryClassStr, isInit)) != ANI_OK) {
LOGE("Object_CallMethod_Ref loadClassMethod failed");
ani_error errorInfo;
env->GetUnhandledError(&errorInfo);
env->ResetError();
break;
}
entryClass = static_cast<ani_class>(entryClassRef);
ani_method entryMethod = nullptr;
if (env->Class_FindMethod(entryClass, "<ctor>", ":", &entryMethod) != ANI_OK) {
LOGE("Class_FindMethod ctor failed");
break;
}
ani_object entryObject = nullptr;
if (env->Object_New(entryClass, entryMethod, &entryObject) != ANI_OK) {
LOGE("Object_New AbcRuntimeLinker failed");
break;
}
return entryObject;
} while (false);
return nullptr;
}
bool ArktsFrontend::Initialize(FrontendType type, const RefPtr<TaskExecutor>& taskExecutor)
{
taskExecutor_ = taskExecutor;
auto mediaQueryCallback = [weakEngine = AceType::WeakClaim(this)](
const std::string& callbackId, const std::string& args) {
auto arktsFrontend = weakEngine.Upgrade();
if (!arktsFrontend) {
return;
}
arktsFrontend->CallbackMediaQuery(callbackId, args);
};
SetMediaQueryCallback(std::move(mediaQueryCallback));
auto navigationLoadCallback = [weakFront = WeakClaim(this)](
const std::string bundleName, const std::string& moduleName, const std::string& pageSourceFile,
bool isSingleton) -> int32_t {
auto frontend = weakFront.Upgrade();
CHECK_NULL_RETURN(frontend, -1);
return frontend->LoadNavDestinationPage(bundleName, moduleName, pageSourceFile, isSingleton) ? 0 : -1;
};
auto container = Container::Current();
if (container) {
auto navigationRoute = container->GetNavigationRoute();
if (navigationRoute) {
navigationRoute->SetLoadPageCallback(std::move(navigationLoadCallback));
}
}
auto instanceId = instanceId_;
AddAvailableInstanceId(instanceId);
return true;
}
void ArktsFrontend::AddAvailableInstanceId(int32_t instanceId)
{
if (instanceId < 0) {
LOGE("Cannot add available instance ID: invalid instance ID");
return;
}
auto container = Container::Current();
if (!container) {
return;
}
void* runtime = container->GetSharedRuntime();
if (runtime) {
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
ani_class uiContextClass;
if (env->FindClass("arkui.base.UIContextUtil.UIContextUtil", &uiContextClass) != ANI_OK) {
LOGE("FindClass arkui.base.UIContextUtil.UIContextUtil failed");
return;
}
if (env->Class_CallStaticMethodByName_Void(uiContextClass, "addAvailableInstanceId", "i:", instanceId) !=
ANI_OK) {
LOGE("Call addAvailableInstanceId method failed");
return;
}
}
}
void ArktsFrontend::RemoveAvailableInstanceId(int32_t instanceId)
{
if (instanceId < 0) {
LOGE("Cannot remove available instance ID: invalid instance ID");
return;
}
auto container = Container::Current();
if (!container) {
return;
}
void* runtime = container->GetSharedRuntime();
if (runtime) {
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
ani_class uiContextClass;
if (env->FindClass("arkui.base.UIContextUtil.UIContextUtil", &uiContextClass) != ANI_OK) {
LOGE("FindClass arkui.base.UIContextUtil.UIContextUtil failed");
return;
}
if (env->Class_CallStaticMethodByName_Void(uiContextClass, "removeAvailableInstanceId", "i:", instanceId) !=
ANI_OK) {
LOGE("Call removeAvailableInstanceId method failed");
return;
}
}
}
bool ArktsFrontend::GetNavigationRegisterClassName(const std::string& pageSourceFile, std::string& className)
{
* Example:
* from pageSourceFile: @normalized:N&&&entry/src/main/ets/pages/MyPage&
* to className: entry.src.main.ets.pages.MyPage.__NavigationBuilderRegisterClass
*/
LOGI("AceNavigation get registerClassName with source: %{public}s", pageSourceFile.c_str());
auto it = pageSourceFile.rfind('&');
if (it == std::string::npos) {
return false;
}
std::string tempClassName = pageSourceFile.substr(0, it);
it = tempClassName.rfind('&');
if (it == std::string::npos) {
return false;
}
tempClassName = tempClassName.substr(it + 1);
if (tempClassName.empty()) {
return false;
}
tempClassName += "/__NavigationBuilderRegisterClass";
std::replace(tempClassName.begin(), tempClassName.end(), '/', '.');
className = tempClassName;
return true;
}
bool ArktsFrontend::LoadNavDestinationPage(const std::string bundleName, const std::string& moduleName,
const std::string& pageSourceFile, bool isSingleton)
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
std::string className;
if (!GetNavigationRegisterClassName(pageSourceFile, className)) {
return false;
}
LOGI("AceNavigation registerClassName: %{public}s", className.c_str());
if (!linkerRef_) {
LOGW("AceNavigation no RuntimeLinker found.");
return false;
}
ani_status status;
ani_string classNameStr;
if ((status = env->String_NewUTF8(className.c_str(), className.length(), &classNameStr)) != ANI_OK) {
LOGW("AceNavigation create className failed, %{public}d", status);
return false;
}
ani_class linkerCls = nullptr;
if ((status = env->FindClass("std.core.RuntimeLinker", &linkerCls)) != ANI_OK) {
LOGW("AceNavigation find RuntimeLinker failed, %{public}d", status);
return false;
}
ani_method loadClassMethod;
if ((status = env->Class_FindMethod(linkerCls, "loadClass",
"C{std.core.String}C{std.core.Boolean}:C{std.core.Class}", &loadClassMethod)) != ANI_OK) {
LOGW("AceNavigation find loadClass failed, %{public}d", status);
return false;
}
ani_object isInit;
if ((status = static_cast<ani_status>(Ani::AniUtils::CreateAniBoolean(env, true, isInit))) != ANI_OK) {
LOGW("AceNavigation create Boolean object failed, %{public}d", status);
return false;
}
ani_ref registerClassRef = nullptr;
if ((status = env->Object_CallMethod_Ref(
(ani_object)linkerRef_, loadClassMethod, ®isterClassRef, classNameStr, isInit)) != ANI_OK) {
LOGW("AceNavigation loadClassMethod failed, %{public}d", status);
ani_error errorInfo;
env->GetUnhandledError(&errorInfo);
env->ResetError();
return false;
}
ani_class registerClass = static_cast<ani_class>(registerClassRef);
ani_static_field staticField;
if ((status = env->Class_FindStaticField(registerClass, "staticBlockTriggerField", &staticField)) != ANI_OK) {
LOGW("AceNavigation find static Field failed, %{public}d", status);
return false;
}
ani_boolean staticFieldValue;
if ((status = env->Class_GetStaticField_Boolean(registerClass, staticField, &staticFieldValue)) != ANI_OK) {
LOGW("AceNavigation get static Field value failed, %{public}d", status);
return false;
}
return true;
}
bool ArktsFrontend::GetNearestNonBootRuntimeLinker()
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
ani_status status;
ani_ref linkerRef;
if ((status = static_cast<ani_status>(Ani::AniUtils::GetNearestNonBootRuntimeLinker(env, linkerRef))) != ANI_OK) {
LOGW("getNearestNonBootRuntimeLinker failed, %{public}d", status);
return false;
}
if ((status = env->GlobalReference_Create((ani_object)linkerRef, &linkerRef_)) != ANI_OK) {
LOGW("create RuntimeLinker global Reference failed, %{public}d", status);
return false;
}
if (!linkerRef_) {
LOGW("get invalid RuntimeLinker!");
return false;
}
return true;
}
UIContentErrorCode ArktsFrontend::RunPage(
const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, UIContentErrorCode::NULL_POINTER);
GetNearestNonBootRuntimeLinker();
if (!pageRouterManager_) {
pageRouterManager_ = NG::PageRouterManagerFactory::CreateManager();
}
ani_class appClass;
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return UIContentErrorCode::INVALID_URL;
}
ani_static_method create;
if (env->Class_FindStaticMethod(
appClass, KOALA_APP_INFO.createMethodName, KOALA_APP_INFO.createMethodSig, &create) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.createMethodName);
return UIContentErrorCode::INVALID_URL;
}
ani_string aniUrl;
env->String_NewUTF8(params.c_str(), params.size(), &aniUrl);
ani_string aniParams;
env->String_NewUTF8("", 0, &aniParams);
ani_string aniName;
env->String_NewUTF8("", 0, &aniName);
NG::EntryLoader entryLoader { env, *(content.get()) };
std::string entryPath = params + ENTRY_SUFFIX;
auto entryPointObj = entryLoader.GetPageEntryObj(entryPath);
auto currentContainer = Container::Current();
CHECK_NULL_RETURN(currentContainer, UIContentErrorCode::NULL_POINTER);
std::string moduleName = currentContainer->GetModuleName();
ani_string module;
env->String_NewUTF8(moduleName.c_str(), moduleName.size(), &module);
ani_boolean enableDebug = ani_boolean(SystemProperties::GetDebugEnabled());
ani_class appConstructorParamClass;
if (env->FindClass(KOALA_APP_INFO.constructorParamClassName, &appConstructorParamClass) != ANI_OK) {
LOGE("Cannot load class %{public}s", KOALA_APP_INFO.constructorParamClassName);
return UIContentErrorCode::INVALID_URL;
}
ani_method paramConstructor;
if (env->Class_FindMethod(appConstructorParamClass, KOALA_APP_INFO.constructorParamCtorMethod,
KOALA_APP_INFO.constructorParamSig, ¶mConstructor) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.constructorParamCtorMethod);
return UIContentErrorCode::INVALID_URL;
}
ani_ref optionalEntry;
env->GetUndefined(&optionalEntry);
ani_object param;
if (env->Object_New(appConstructorParamClass, paramConstructor, ¶m, aniUrl, aniParams, aniName, false, module,
optionalEntry, entryPointObj ? entryPointObj : optionalEntry,
enableDebug) != ANI_OK) {
LOGE("Fail to create ApplicationConstructorParam");
return UIContentErrorCode::INVALID_URL;
}
ani_ref appLocal;
if (env->Class_CallStaticMethod_Ref(appClass, create, &appLocal, param) != ANI_OK) {
LOGE("createApplication returned null");
return UIContentErrorCode::INVALID_URL;
}
env->GlobalReference_Create(appLocal, &app_);
if (taskExecutor_ == nullptr) {
LOGE("taskExecutor is nullptr");
return UIContentErrorCode::NULL_POINTER;
}
taskExecutor_->PostTask([weak = WeakClaim(this)]() {
auto frontend = weak.Upgrade();
CHECK_NULL_VOID(frontend);
auto* env = Ani::AniUtils::GetAniEnv(frontend->GetVM());
CHECK_NULL_VOID(env);
ani_class appClass;
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return;
}
ani_method start;
if (env->Class_FindMethod(appClass, KOALA_APP_INFO.startMethodName, KOALA_APP_INFO.startMethodSig, &start) !=
ANI_OK) {
LOGE("find start method returned null");
return;
}
ani_long result;
if (env->Object_CallMethod_Long(static_cast<ani_object>(frontend->GetApp()), start, &result, ANI_FALSE) !=
ANI_OK) {
LOGE("call start method returned null");
return;
}
}, TaskExecutor::TaskType::JS, "ArkUIRunPageUrl");
CHECK_NULL_RETURN(pipeline_, UIContentErrorCode::NULL_POINTER);
pipeline_->SetVsyncListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
RunArkoalaEventLoop(env, app);
});
pipeline_->SetAsyncEventsHookListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
FireAllArkoalaAsyncEvents(env, app);
});
return UIContentErrorCode::NO_ERRORS;
}
UIContentErrorCode ArktsFrontend::RunPage(const std::string& url, const std::string& params)
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, UIContentErrorCode::INVALID_URL);
ani_class appClass;
EntryLoader entryLoader(url, env);
GetNearestNonBootRuntimeLinker();
if (!pageRouterManager_) {
pageRouterManager_ = NG::PageRouterManagerFactory::CreateManager();
}
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return UIContentErrorCode::INVALID_URL;
}
ani_static_method create;
if (env->Class_FindStaticMethod(
appClass, KOALA_APP_INFO.createMethodName, KOALA_APP_INFO.createMethodSig, &create) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.createMethodName);
return UIContentErrorCode::INVALID_URL;
}
ani_string aniUrl;
env->String_NewUTF8(url.c_str(), url.size(), &aniUrl);
ani_string aniParams;
env->String_NewUTF8(params.c_str(), params.size(), &aniParams);
ani_string aniName;
env->String_NewUTF8("", 0, &aniName);
ani_ref appLocal;
ani_ref optionalEntry;
env->GetUndefined(&optionalEntry);
auto entryPointObj = url == "__INTEROP__" ? nullptr : entryLoader.GetPageEntryObj();
auto legacyEntryPointObj = url == "__INTEROP__" ? nullptr : LegacyLoadPage(env);
auto currentContainer = Container::Current();
CHECK_NULL_RETURN(currentContainer, UIContentErrorCode::NULL_POINTER);
std::string moduleName = currentContainer->GetModuleName();
ani_string module;
env->String_NewUTF8(moduleName.c_str(), moduleName.size(), &module);
ani_boolean enableDebug = ani_boolean(SystemProperties::GetDebugEnabled());
ani_class appConstructorParamClass;
if (env->FindClass(KOALA_APP_INFO.constructorParamClassName, &appConstructorParamClass) != ANI_OK) {
LOGE("Cannot load class %{public}s", KOALA_APP_INFO.constructorParamClassName);
return UIContentErrorCode::INVALID_URL;
}
ani_method paramConstructor;
if (env->Class_FindMethod(appConstructorParamClass, KOALA_APP_INFO.constructorParamCtorMethod,
KOALA_APP_INFO.constructorParamSig, ¶mConstructor) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.constructorParamCtorMethod);
return UIContentErrorCode::INVALID_URL;
}
ani_object param;
if (env->Object_New(appConstructorParamClass, paramConstructor, ¶m, aniUrl, aniParams, aniName, false, module,
legacyEntryPointObj ? legacyEntryPointObj : optionalEntry, entryPointObj ? entryPointObj : optionalEntry,
enableDebug) != ANI_OK) {
LOGE("Fail to create ApplicationConstructorParam");
return UIContentErrorCode::INVALID_URL;
}
if (env->Class_CallStaticMethod_Ref(appClass, create, &appLocal, param) != ANI_OK) {
LOGE("createApplication returned null");
return UIContentErrorCode::INVALID_URL;
}
env->GlobalReference_Create(appLocal, &app_);
if (taskExecutor_ == nullptr) {
LOGE("taskExecutor is nullptr");
return UIContentErrorCode::NULL_POINTER;
}
taskExecutor_->PostTask([weak = WeakClaim(this)]() {
auto frontend = weak.Upgrade();
CHECK_NULL_VOID(frontend);
auto* env = Ani::AniUtils::GetAniEnv(frontend->GetVM());
CHECK_NULL_VOID(env);
ani_class appClass;
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return;
}
ani_method start;
if (env->Class_FindMethod(appClass, KOALA_APP_INFO.startMethodName, KOALA_APP_INFO.startMethodSig, &start) !=
ANI_OK) {
LOGE("find start method returned null");
return;
}
ani_long result;
if (env->Object_CallMethod_Long(static_cast<ani_object>(frontend->GetApp()), start, &result, ANI_FALSE) !=
ANI_OK) {
LOGE("call start method returned null");
return;
}
}, TaskExecutor::TaskType::JS, "ArkUIRunPageUrl");
CHECK_NULL_RETURN(pipeline_, UIContentErrorCode::NULL_POINTER);
pipeline_->SetVsyncListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
RunArkoalaEventLoop(env, app);
});
pipeline_->SetAsyncEventsHookListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
FireAllArkoalaAsyncEvents(env, app);
});
return UIContentErrorCode::NO_ERRORS;
}
UIContentErrorCode ArktsFrontend::RunPageByNamedRouter(const std::string& name, const std::string& params)
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, UIContentErrorCode::INVALID_URL);
ani_class appClass;
GetNearestNonBootRuntimeLinker();
if (!pageRouterManager_) {
pageRouterManager_ = NG::PageRouterManagerFactory::CreateManager();
}
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return UIContentErrorCode::INVALID_URL;
}
ani_static_method create;
if (env->Class_FindStaticMethod(
appClass, KOALA_APP_INFO.createMethodName, KOALA_APP_INFO.createMethodSig, &create) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.createMethodName);
return UIContentErrorCode::INVALID_URL;
}
ani_string aniUrl;
env->String_NewUTF8("", 0, &aniUrl);
ani_string aniParams;
env->String_NewUTF8(params.c_str(), params.size(), &aniParams);
ani_string aniName;
env->String_NewUTF8(name.c_str(), name.size(), &aniName);
ani_ref appLocal;
ani_ref optionalEntry;
env->GetUndefined(&optionalEntry);
auto currentContainer = Container::Current();
CHECK_NULL_RETURN(currentContainer, UIContentErrorCode::NULL_POINTER);
std::string moduleName = currentContainer->GetModuleName();
ani_string module;
env->String_NewUTF8(moduleName.c_str(), moduleName.size(), &module);
ani_boolean enableDebug = ani_boolean(SystemProperties::GetDebugEnabled());
ani_class appConstructorParamClass;
if (env->FindClass(KOALA_APP_INFO.constructorParamClassName, &appConstructorParamClass) != ANI_OK) {
LOGE("Cannot load class %{public}s", KOALA_APP_INFO.constructorParamClassName);
return UIContentErrorCode::INVALID_URL;
}
ani_method paramConstructor;
if (env->Class_FindMethod(appConstructorParamClass, KOALA_APP_INFO.constructorParamCtorMethod,
KOALA_APP_INFO.constructorParamSig, ¶mConstructor) != ANI_OK) {
LOGE("Cannot find create method %{public}s", KOALA_APP_INFO.constructorParamCtorMethod);
return UIContentErrorCode::INVALID_URL;
}
ani_object param;
if (env->Object_New(appConstructorParamClass, paramConstructor, ¶m, aniUrl, aniParams, aniName, false, module,
optionalEntry, optionalEntry, enableDebug) != ANI_OK) {
LOGE("Fail to create ApplicationConstructorParam");
return UIContentErrorCode::INVALID_URL;
}
if (env->Class_CallStaticMethod_Ref(appClass, create, &appLocal, param) != ANI_OK) {
LOGE("createApplication returned null");
return UIContentErrorCode::INVALID_URL;
}
env->GlobalReference_Create(appLocal, &app_);
if (taskExecutor_ == nullptr) {
LOGE("taskExecutor is nullptr");
return UIContentErrorCode::NULL_POINTER;
}
taskExecutor_->PostTask([weak = WeakClaim(this)]() {
auto frontend = weak.Upgrade();
CHECK_NULL_VOID(frontend);
auto* env = Ani::AniUtils::GetAniEnv(frontend->GetVM());
CHECK_NULL_VOID(env);
ani_class appClass;
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className);
return;
}
ani_method start;
if (env->Class_FindMethod(appClass, KOALA_APP_INFO.startMethodName, KOALA_APP_INFO.startMethodSig, &start) !=
ANI_OK) {
LOGE("find start method returned null");
return;
}
ani_long result;
if (env->Object_CallMethod_Long(static_cast<ani_object>(frontend->GetApp()), start, &result, ANI_FALSE) !=
ANI_OK) {
LOGE("call start method returned null");
return;
}
}, TaskExecutor::TaskType::JS, "ArkUIRunPageUrl");
CHECK_NULL_RETURN(pipeline_, UIContentErrorCode::NULL_POINTER);
pipeline_->SetVsyncListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
RunArkoalaEventLoop(env, app);
});
pipeline_->SetAsyncEventsHookListener([vm = vm_, app = app_]() {
auto* env = Ani::AniUtils::GetAniEnv(vm);
FireAllArkoalaAsyncEvents(env, app);
});
return UIContentErrorCode::NO_ERRORS;
}
void ArktsFrontend::AttachPipelineContext(const RefPtr<PipelineBase>& context)
{
pipeline_ = DynamicCast<NG::PipelineContext>(context);
if (accessibilityManager_) {
accessibilityManager_->SetPipelineContext(context);
accessibilityManager_->InitializeCallback();
}
}
void ArktsFrontend::AttachSubPipelineContext(const RefPtr<PipelineBase>& context)
{
if (!context) {
return;
}
accessibilityManager_->AddSubPipelineContext(context);
accessibilityManager_->RegisterSubWindowInteractionOperation(context->GetWindowId());
}
ani_ref ArktsFrontend::GetSharedStorage(int32_t id)
{
int32_t currentInstance = id;
if (currentInstance >= MIN_SUBCONTAINER_ID && currentInstance < MIN_PLUGIN_SUBCONTAINER_ID) {
currentInstance = SubwindowManager::GetInstance()->GetParentContainerId(currentInstance);
}
auto it = storageMap_.find(currentInstance);
if (it == storageMap_.end()) {
LOGW("LocalStorage with ID %{public}d not found!", currentInstance);
return nullptr;
}
return reinterpret_cast<ani_ref>(it->second);
}
void ArktsFrontend::Destroy()
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
env->GlobalReference_Delete(app_);
app_ = nullptr;
handleMessageMethod_ = nullptr;
}
ani_object ArktsFrontend::GetUIContext(int32_t instanceId)
{
ani_object result = nullptr;
ani_status status;
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, result);
ani_class uiContextClass;
if ((status = env->FindClass("arkui.base.UIContextUtil.UIContextUtil", &uiContextClass)) != ANI_OK) {
LOGE("FindClass UIContext failed, %{public}d", status);
return result;
}
ani_ref aniRef = nullptr;
if ((status = env->Class_CallStaticMethodByName_Ref(uiContextClass, "getOrCreateUIContextById",
"i:C{@ohos.arkui.UIContext.UIContext}", &aniRef, instanceId)) != ANI_OK) {
LOGE("Class_CallStaticMethodByName_Ref failed, %{public}d", status);
return result;
}
result = reinterpret_cast<ani_object>(aniRef);
return result;
}
void* ArktsFrontend::GetEnv()
{
return Ani::AniUtils::GetAniEnv(vm_);
}
ani_ref ArktsFrontend::GetApp()
{
return app_;
}
ani_vm *ArktsFrontend::GetVM()
{
return vm_;
}
void ArktsFrontend::PushExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* jsNode)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->PushExtender(routerPageInfo, std::move(finishCallback), jsNode);
}
void ArktsFrontend::PushNamedRouteExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* jsNode)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->PushNamedRouteExtender(routerPageInfo, std::move(finishCallback), jsNode);
}
void* ArktsFrontend::CreateDynamicExtender(const std::string& url, bool recoverable)
{
CHECK_NULL_RETURN(pageRouterManager_, nullptr);
auto subFrontend = subFrontend_.Upgrade();
CHECK_NULL_RETURN(subFrontend, nullptr);
auto pageId = pageRouterManager_->GenerateNextPageId();
isUseSubFrontendManagerNeeded_ = true;
auto* pageNode = subFrontend->CreateDynamicPage(pageId, url, "", recoverable);
isUseSubFrontendManagerNeeded_ = false;
CHECK_NULL_RETURN(pageNode, nullptr);
return pageNode;
}
void ArktsFrontend::PushDynamicExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* pageNodeRawPtr)
{
CHECK_NULL_VOID(pageRouterManager_);
CHECK_NULL_VOID(pageNodeRawPtr);
auto pageNode = AceType::WeakClaim(static_cast<NG::FrameNode*>(pageNodeRawPtr)).Upgrade();
CHECK_NULL_VOID(pageNode);
if (pageNode->RefCount() != 2) {
LOGE("AceRouter pageNode for PushDynamicExtender has wrong RefCount: %{public}d", pageNode->RefCount());
}
if (pageNode->RefCount() > 1) {
pageNode->DecRefCount();
}
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->PushDynamicExtender(
routerPageInfo, std::move(finishCallback), pageNode);
}
void ArktsFrontend::ReplaceDynamicExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* pageNodeRawPtr)
{
CHECK_NULL_VOID(pageRouterManager_);
CHECK_NULL_VOID(pageNodeRawPtr);
auto pageNode = AceType::WeakClaim(static_cast<NG::FrameNode*>(pageNodeRawPtr)).Upgrade();
CHECK_NULL_VOID(pageNode);
if (pageNode->RefCount() != 2) {
LOGE("AceRouter pageNode for ReplaceDynamicExtender has wrong RefCount: %{public}d", pageNode->RefCount());
}
if (pageNode->RefCount() > 1) {
pageNode->DecRefCount();
}
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->ReplaceDynamicExtender(routerPageInfo, std::move(finishCallback), pageNode);
}
void ArktsFrontend::PushFromDynamicExtender(const std::string& url, const std::string& params, bool recoverable,
const std::function<void(const std::string&, int32_t)>& callback, uint32_t routerMode)
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
CHECK_NULL_VOID(linkerRef_);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return;
}
ani_static_method pushFromDynamicMethod;
const char* methodName = "pushFromDynamic";
const char* methodMangling = "iC{std.core.String}C{std.core.String}C{std.core.RuntimeLinker}:";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &pushFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return;
}
ani_string urlStr;
if ((status = env->String_NewUTF8(url.c_str(), url.size(), &urlStr)) != ANI_OK) {
LOGE("AceRouter failed to create url string, status:%{public}d", status);
return;
}
ani_string paramStr;
if ((status = env->String_NewUTF8(params.c_str(), params.size(), ¶mStr)) != ANI_OK) {
LOGE("AceRouter failed to create params string, status:%{public}d", status);
return;
}
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Void(routerUtilCls, pushFromDynamicMethod,
static_cast<ani_int>(instanceId), urlStr, paramStr, (ani_object)linkerRef_)) != ANI_OK) {
LOGE("AceRouter failed to call pushFromDynamic, status:%{public}d", status);
return;
}
}
void ArktsFrontend::ReplaceFromDynamicExtender(const std::string& url, const std::string& params, bool recoverable,
const std::function<void(const std::string&, int32_t)>& callback, uint32_t routerMode)
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
CHECK_NULL_VOID(linkerRef_);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return;
}
ani_static_method replaceFromDynamicMethod;
const char* methodName = "replaceFromDynamic";
const char* methodMangling = "iC{std.core.String}C{std.core.String}C{std.core.RuntimeLinker}:";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &replaceFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return;
}
ani_string urlStr;
if ((status = env->String_NewUTF8(url.c_str(), url.size(), &urlStr)) != ANI_OK) {
LOGE("AceRouter failed to create url string, status:%{public}d", status);
return;
}
ani_string paramStr;
if ((status = env->String_NewUTF8(params.c_str(), params.size(), ¶mStr)) != ANI_OK) {
LOGE("AceRouter failed to create params string, status:%{public}d", status);
return;
}
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Void(routerUtilCls, replaceFromDynamicMethod,
static_cast<ani_int>(instanceId), urlStr, paramStr, (ani_object)linkerRef_)) != ANI_OK) {
LOGE("AceRouter failed to call replaceFromDynamic, status:%{public}d", status);
return;
}
}
void ArktsFrontend::BackFromDynamicExtender(const std::string& url, const std::string& params)
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
CHECK_NULL_VOID(linkerRef_);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return;
}
ani_static_method backFromDynamicMethod;
const char* methodName = "backFromDynamic";
const char* methodMangling = "iC{std.core.String}C{std.core.String}C{std.core.RuntimeLinker}:";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &backFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return;
}
ani_string urlStr;
if ((status = env->String_NewUTF8(url.c_str(), url.size(), &urlStr)) != ANI_OK) {
LOGE("AceRouter failed to create url string, status:%{public}d", status);
return;
}
ani_string paramStr;
if ((status = env->String_NewUTF8(params.c_str(), params.size(), ¶mStr)) != ANI_OK) {
LOGE("AceRouter failed to create params string, status:%{public}d", status);
return;
}
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Void(routerUtilCls, backFromDynamicMethod,
static_cast<ani_int>(instanceId), urlStr, paramStr, (ani_object)linkerRef_)) != ANI_OK) {
LOGE("AceRouter failed to call backFromDynamic, status:%{public}d", status);
return;
}
}
void ArktsFrontend::ClearFromDynamicExtender()
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
CHECK_NULL_VOID(linkerRef_);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return;
}
ani_static_method clearFromDynamicMethod;
const char* methodName = "clearFromDynamic";
const char* methodMangling = "iC{std.core.RuntimeLinker}:";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &clearFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return;
}
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Void(routerUtilCls, clearFromDynamicMethod,
static_cast<ani_int>(instanceId), (ani_object)linkerRef_)) != ANI_OK) {
LOGE("AceRouter failed to call clearFromDynamic, status:%{public}d", status);
return;
}
}
int32_t ArktsFrontend::GetLengthFromDynamicExtender()
{
CHECK_NULL_RETURN(vm_, 0);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, 0);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return 0;
}
ani_static_method getLengthFromDynamicMethod;
const char* methodName = "getLengthFromDynamic";
const char* methodMangling = "i:C{std.core.String}";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getLengthFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return 0;
}
ani_ref resultStr;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Ref(routerUtilCls, getLengthFromDynamicMethod,
&resultStr, static_cast<ani_int>(instanceId))) != ANI_OK) {
LOGE("AceRouter failed to call getLengthFromDynamic, status:%{public}d", status);
return 0;
}
auto lengthStr = Ani::AniUtils::ANIStringToStdString(env, reinterpret_cast<ani_string>(resultStr));
int32_t length = std::atoi(lengthStr.c_str());
return length;
}
int32_t ArktsFrontend::GetStackSizeFromDynamicExtender()
{
CHECK_NULL_RETURN(vm_, 0);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, 0);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return 0;
}
ani_static_method getStackSizeFromDynamicMethod;
const char* methodName = "getStackSizeFromDynamic";
const char* methodMangling = "i:i";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getStackSizeFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return 0;
}
ani_int result;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Int(routerUtilCls, getStackSizeFromDynamicMethod,
&result, static_cast<ani_int>(instanceId))) != ANI_OK) {
LOGE("AceRouter failed to call getStackSizeFromDynamic, status:%{public}d", status);
return 0;
}
return static_cast<int>(result);
}
std::string ArktsFrontend::GetParamsFromDynamicExtender()
{
CHECK_NULL_RETURN(vm_, "");
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, "");
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return "";
}
ani_static_method getParamsFromDynamicMethod;
const char* methodName = "getParamsFromDynamic";
const char* methodMangling = "i:C{std.core.String}";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getParamsFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return "";
}
ani_ref resultStr;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Ref(routerUtilCls, getParamsFromDynamicMethod,
&resultStr, static_cast<ani_int>(instanceId))) != ANI_OK) {
LOGE("AceRouter failed to call %{public}s, status:%{public}d", methodName, status);
return "";
}
auto paramsStr = Ani::AniUtils::ANIStringToStdString(env, reinterpret_cast<ani_string>(resultStr));
return paramsStr;
}
bool ArktsFrontend::GetStateByUrlFromDynamicExtender(const std::string& url, std::vector<RouterStateInfo>& stateArray)
{
CHECK_NULL_RETURN(vm_, false);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return false;
}
ani_static_method getStateByUrlFromDynamicMethod;
const char* methodName = "getStateByUrlFromDynamic";
const char* methodMangling = "iC{std.core.String}:C{std.core.Array}";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getStateByUrlFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_string urlStr;
if ((status = env->String_NewUTF8(url.c_str(), url.size(), &urlStr)) != ANI_OK) {
LOGE("AceRouter failed to create url string, status:%{public}d", status);
return false;
}
ani_ref resultArray;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Ref(routerUtilCls, getStateByUrlFromDynamicMethod,
&resultArray, static_cast<ani_int>(instanceId), urlStr)) != ANI_OK) {
LOGE("AceRouter failed to call %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_size stateCount = 0;
if ((status = env->Array_GetLength(static_cast<ani_array>(resultArray), &stateCount)) != ANI_OK) {
LOGE("AceRouter failed to get Array length, status:%{public}d", status);
return false;
}
std::vector<RouterStateInfo> tempStates;
for (ani_size idx = 0; idx < stateCount; ++idx) {
ani_ref result;
if ((status = env->Array_Get(static_cast<ani_array>(resultArray), idx, &result)) != ANI_OK) {
LOGE("AceRouter failed to get Array item[%{public}d], status:%{public}d", (int32_t)idx, status);
return false;
}
RouterStateInfo state;
if (!ParseRouterStateInfo(env, result, state)) {
return false;
}
tempStates.push_back(state);
}
std::swap(tempStates, stateArray);
return true;
}
bool ArktsFrontend::GetStateByIndexFromDynamicExtender(int32_t index, RouterStateInfo& state)
{
CHECK_NULL_RETURN(vm_, false);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return false;
}
ani_static_method getStateByIndexFromDynamicMethod;
const char* methodName = "getStateByIndexFromDynamic";
const char* methodMangling = "ii:C{arkui.base.Router.InnerRouterState}";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getStateByIndexFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_ref result;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Ref(routerUtilCls, getStateByIndexFromDynamicMethod,
&result, static_cast<ani_int>(instanceId), static_cast<ani_int>(index))) != ANI_OK) {
LOGE("AceRouter failed to call %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_boolean isUndefined;
if ((status = env->Reference_IsUndefined(result, &isUndefined)) != ANI_OK) {
LOGE("AceRouter failed to call Reference_IsUndefined, status:%{public}d", status);
return false;
}
if (isUndefined) {
return false;
}
return ParseRouterStateInfo(env, result, state);
}
bool ArktsFrontend::GetStateFromDynamicExtender(RouterStateInfo& state)
{
CHECK_NULL_RETURN(vm_, false);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return false;
}
ani_static_method getStateFromDynamicMethod;
const char* methodName = "getStateFromDynamic";
const char* methodMangling = "i:C{arkui.base.Router.InnerRouterState}";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &getStateFromDynamicMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_ref result;
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Ref(routerUtilCls, getStateFromDynamicMethod,
&result, static_cast<ani_int>(instanceId))) != ANI_OK) {
LOGE("AceRouter failed to call %{public}s, status:%{public}d", methodName, status);
return false;
}
ani_boolean isUndefined;
if ((status = env->Reference_IsUndefined(result, &isUndefined)) != ANI_OK) {
LOGE("AceRouter failed to call Reference_IsUndefined, status:%{public}d", status);
return false;
}
if (isUndefined) {
return false;
}
return ParseRouterStateInfo(env, result, state);
}
int32_t ArktsFrontend::GetCurrentPageIndex() const
{
CHECK_NULL_RETURN(pageRouterManager_, -1);
return pageRouterManager_->GetCurrentPageIndex();
}
UIContentErrorCode ArktsFrontend::RunIntentPage()
{
if (pageRouterManager_) {
taskExecutor_->PostTask(
[weakPtr = WeakPtr<NG::PageRouterManager>(pageRouterManager_)]() {
auto pageRouterManager = weakPtr.Upgrade();
CHECK_NULL_VOID(pageRouterManager);
pageRouterManager->RunIntentPageExtender();
},
TaskExecutor::TaskType::JS, "ArkUIRunIntentPage");
return UIContentErrorCode::NO_ERRORS;
}
return UIContentErrorCode::NULL_POINTER;
}
void ArktsFrontend::CallRunIntentPageFromNative(const std::string& url, const std::string& paramStr)
{
CHECK_NULL_VOID(vm_);
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
ani_status status;
ani_class routerUtilCls;
const char* clsMangling = "arkui.base.Router.RouterUtil";
if ((status = env->FindClass(clsMangling, &routerUtilCls)) != ANI_OK) {
LOGE("AceRouter Cannot find class: %{public}s, status:%{public}d", clsMangling, status);
return;
}
ani_static_method runIntentPageMethod;
const char* methodName = "runIntentPageFromNative";
const char* methodMangling = "iC{std.core.String}C{std.core.String}C{std.core.RuntimeLinker}:";
if ((status = env->Class_FindStaticMethod(
routerUtilCls, methodName, methodMangling, &runIntentPageMethod)) != ANI_OK) {
LOGE("AceRouter Cannot find method: %{public}s, status:%{public}d", methodName, status);
return;
}
ani_string urlStr;
if ((status = env->String_NewUTF8(url.c_str(), url.size(), &urlStr)) != ANI_OK) {
LOGE("AceRouter failed to create url string, status:%{public}d", status);
return;
}
ani_string paramAniStr;
if ((status = env->String_NewUTF8(paramStr.c_str(), paramStr.size(), ¶mAniStr)) != ANI_OK) {
LOGE("AceRouter failed to create param string, status:%{public}d", status);
return;
}
auto instanceId = Container::CurrentIdSafely();
if ((status = env->Class_CallStaticMethod_Void(routerUtilCls, runIntentPageMethod,
static_cast<ani_int>(instanceId), urlStr, paramAniStr, (ani_object)linkerRef_)) != ANI_OK) {
LOGE("AceRouter failed to call runIntentPageFromNative, status:%{public}d", status);
return;
}
}
UIContentErrorCode ArktsFrontend::SetRouterIntentInfo(const std::string& intentInfoSerialized, bool isColdStart,
const std::function<void()>&& loadPageCallback)
{
taskExecutor_->PostTask(
[weakPtr = WeakPtr<NG::PageRouterManager>(pageRouterManager_), intentInfoSerialized, isColdStart,
callback = std::move(loadPageCallback)]() {
auto pageRouterManager = weakPtr.Upgrade();
CHECK_NULL_VOID(pageRouterManager);
pageRouterManager->SetRouterIntentInfo(intentInfoSerialized, isColdStart, std::move(callback));
},
TaskExecutor::TaskType::JS, "ArkUISetRouterIntentInfo");
return UIContentErrorCode::NO_ERRORS;
}
void ArktsFrontend::ReplaceExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* jsNode)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->ReplaceExtender(routerPageInfo, std::move(finishCallback), jsNode);
}
void ArktsFrontend::ReplaceNamedRouteExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* jsNode)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->ReplaceNamedRouteExtender(routerPageInfo, std::move(finishCallback), jsNode);
}
void ArktsFrontend::RunPageExtender(
const PageRouterOptions& options, std::function<void()>&& finishCallback, void* jsNode)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = options.url;
routerPageInfo.params = options.params;
routerPageInfo.recoverable = options.recoverable;
routerPageInfo.routerMode = static_cast<NG::RouterMode>(options.routerMode);
routerPageInfo.errorCallback = options.errorCallback;
routerPageInfo.isNamedRouterMode = options.isNamedRouterMode;
pageRouterManager_->RunPageExtender(routerPageInfo, std::move(finishCallback), jsNode);
}
void ArktsFrontend::BackExtender(const std::string& url, const std::string& params)
{
CHECK_NULL_VOID(pageRouterManager_);
NG::RouterPageInfo routerPageInfo;
routerPageInfo.url = url;
routerPageInfo.params = params;
pageRouterManager_->BackWithTargetExtender(routerPageInfo);
}
void ArktsFrontend::BackToIndexExtender(int32_t index, const std::string& params)
{
CHECK_NULL_VOID(pageRouterManager_);
pageRouterManager_->BackToIndexWithTargetExtender(index, params);
}
void ArktsFrontend::ClearExtender()
{
CHECK_NULL_VOID(pageRouterManager_);
pageRouterManager_->Clear();
}
void ArktsFrontend::ShowAlertBeforeBackPageExtender(const std::string& url)
{
CHECK_NULL_VOID(pageRouterManager_);
auto dialogCallback = [](int32_t callbackType) {};
pageRouterManager_->EnableAlertBeforeBackPageExtender(url, std::move(dialogCallback));
}
void ArktsFrontend::HideAlertBeforeBackPageExtender()
{
CHECK_NULL_VOID(pageRouterManager_);
pageRouterManager_->DisableAlertBeforeBackPage();
}
bool ArktsFrontend::OnBackPressed()
{
CHECK_NULL_RETURN(pageRouterManager_, false);
auto pageNode = pageRouterManager_->GetCurrentPageNode();
CHECK_NULL_RETURN(pageNode, false);
auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
CHECK_NULL_RETURN(pagePattern, false);
if (pagePattern->OnBackPressed()) {
return true;
}
return pageRouterManager_->Pop();
}
void ArktsFrontend::OnShow()
{
CHECK_NULL_VOID(pageRouterManager_);
auto pageNode = pageRouterManager_->GetCurrentPageNode();
CHECK_NULL_VOID(pageNode);
auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
CHECK_NULL_VOID(pagePattern);
pagePattern->OnShow(true);
}
void ArktsFrontend::OnHide()
{
CHECK_NULL_VOID(pageRouterManager_);
auto pageNode = pageRouterManager_->GetCurrentPageNode();
CHECK_NULL_VOID(pageNode);
auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
CHECK_NULL_VOID(pagePattern);
pagePattern->OnHide(true);
}
void ArktsFrontend::OpenStateMgmtInterop()
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
ani_status state;
static const char* moduleName = "arkui.component.interop";
ani_module interopModule;
state = env->FindModule(moduleName, &interopModule);
if (state != ANI_OK) {
LOGE("Cannot find module arkui.component.interop %{public}d", state);
return;
}
ani_function fn;
state = env->Module_FindFunction(interopModule, "openInterop", ":", &fn);
if (state != ANI_OK) {
LOGE("Cannot find function openInterop in module %{public}d", state);
}
state = env->Function_Call_Void(fn);
if (state != ANI_OK) {
LOGE("Function_Call openInterop failed %{public}d", state);
}
return;
}
napi_value ArktsFrontend::GetContextValue()
{
auto container = Container::Current();
CHECK_NULL_RETURN(container, nullptr);
auto type = container->GetFrontendType();
if (type == FrontendType::STATIC_HYBRID_DYNAMIC && container->GetSubFrontend()) {
return container->GetSubFrontend()->GetContextValue();
} else {
return nullptr;
}
}
bool ArktsFrontend::HandleMessage(void *frameNode, int32_t type, const std::string& param)
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_RETURN(env, false);
CHECK_NULL_RETURN(app_, false);
CHECK_NULL_RETURN(frameNode, false);
ani_status status = ANI_ERROR;
if (handleMessageMethod_ == nullptr) {
ani_class appClass;
if ((status = env->FindClass(KOALA_APP_INFO.className, &appClass)) != ANI_OK) {
LOGE("Call handleMessage failed due to FindClass failed, status : %{public}d", status);
return false;
}
ani_method handleMessageMethod = nullptr;
if ((status = env->Class_FindMethod(appClass, KOALA_APP_INFO.handleMessageMethodName,
KOALA_APP_INFO.handleMessageMethodSig, &handleMessageMethod)) != ANI_OK) {
LOGE("Call handleMessage failed due to Class_FindMethod failed, status : %{public}d", status);
return false;
}
handleMessageMethod_ = handleMessageMethod;
}
ani_long ptrAni = reinterpret_cast<ani_long>(frameNode);
ani_int typeAni = type;
ani_string paramStr;
env->String_NewUTF8(param.c_str(), param.length(), ¶mStr);
ani_boolean result;
if ((status = env->Object_CallMethod_Boolean(static_cast<ani_object>(app_),
handleMessageMethod_, &result, ptrAni, typeAni, paramStr)) != ANI_OK) {
LOGE("Call handleMessage failed, status: %{public}d", status);
return false;
}
return result == ANI_TRUE;
}
void ArktsFrontend::SetHostContext(int32_t instanceId, ani_ref* context)
{
std::shared_ptr<ani_ref> shared_ptr(context);
Framework::AniContextModule::AddAniContext(instanceId, shared_ptr);
}
ani_ref* ArktsFrontend::GetHostContext()
{
return Framework::AniContextModule::GetAniContext().get();
}
void ArktsFrontend::NotifyArkoalaConfigurationChange(bool isNeedUpdate)
{
if (!isNeedUpdate) {
return;
}
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
CHECK_NULL_VOID(app_);
ani_status status;
if ((status = env->Object_CallMethodByName_Void((ani_object)app_, "notifyConfigurationChange", ":")) != ANI_OK) {
LOGE("Call notifyConfigurationChange error");
return;
}
}
void ArktsFrontend::InitXBarProxy()
{
auto* env = Ani::AniUtils::GetAniEnv(vm_);
CHECK_NULL_VOID(env);
ani_class appClass;
if (env->FindClass("C{arkui.XBarProxy.XBarProxy}", &appClass) != ANI_OK) {
LOGE("Cannot load main class arkui.XBarProxy.XBarProxy");
return;
}
ani_static_method create;
if (env->Class_FindStaticMethod(appClass, "initializeXBarProxy", ":", &create) != ANI_OK) {
LOGE("Cannot find create methodinitializeXBarProxy");
return;
}
ani_ref result;
if (env->Class_CallStaticMethod_Void(appClass, create, &result) != ANI_OK) {
LOGE("initializeXBarProxy returned null");
}
}
void* ArktsFrontend::preloadArkTSRuntime = nullptr;
void ArktsFrontend::PreloadAceModule(void* aniEnv)
{
ArktsFrontend::preloadArkTSRuntime = aniEnv;
auto* env = reinterpret_cast<ani_env*>(aniEnv);
ani_class appClass;
if (env->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) {
LOGE("PreloadAceModule: Cannot load main class %{public}s", KOALA_APP_INFO.className);
return;
}
ani_static_method create;
if (env->Class_FindStaticMethod(
appClass, KOALA_APP_INFO.registerNativeModule, KOALA_APP_INFO.registerNativeModuleSig, &create) != ANI_OK) {
LOGE("PreloadAceModule: Cannot find method %{public}s", KOALA_APP_INFO.registerNativeModule);
return;
}
ani_ref appLocal;
env->Class_CallStaticMethod_Void(appClass, create, &appLocal);
}
void ArktsFrontend::OnLayoutChildrenCompleted(const std::string& componentId)
{
auto iter = layoutChildrenCallbacks_.find(componentId);
if (iter == layoutChildrenCallbacks_.end()) {
return;
}
if (taskExecutor_ == nullptr) {
return;
}
auto&& observer = iter->second;
taskExecutor_->PostTask([observer] { (*observer)(); }, TaskExecutor::TaskType::JS, "ArkUIDrawChildrenCompleted");
}
bool ArktsFrontend::IsLayoutChildrenCallbackFuncExist(const std::string& componentId)
{
auto iter = layoutChildrenCallbacks_.find(componentId);
if (iter == layoutChildrenCallbacks_.end()) {
return false;
}
return iter->second->HasCallback();
}
void ArktsFrontend::OnLayoutCompleted(int32_t uniqueId)
{
auto iter = uniqueIdLayoutCallbacks_.find(uniqueId);
if (iter == uniqueIdLayoutCallbacks_.end()) {
return;
}
if (taskExecutor_ == nullptr) {
return;
}
auto&& observer = iter->second;
taskExecutor_->PostTask([observer] { (*observer)(); }, TaskExecutor::TaskType::JS, "ArkUILayoutCompleted");
}
void ArktsFrontend::OnDrawCompleted(int32_t uniqueId)
{
auto iter = uniqueIdDrawCallbacks_.find(uniqueId);
if (iter == uniqueIdDrawCallbacks_.end()) {
return;
}
if (taskExecutor_ == nullptr) {
return;
}
auto&& observer = iter->second;
taskExecutor_->PostTask([observer] { (*observer)(); }, TaskExecutor::TaskType::JS, "ArkUIDrawCompleted");
}
void ArktsFrontend::OnDrawChildrenCompleted(int32_t uniqueId)
{
auto iter = uniqueIdDrawChildrenCallbacks_.find(uniqueId);
if (iter == uniqueIdDrawChildrenCallbacks_.end()) {
return;
}
if (taskExecutor_ == nullptr) {
return;
}
auto&& observer = iter->second;
taskExecutor_->PostTask([observer] { (*observer)(); }, TaskExecutor::TaskType::JS, "ArkUIDrawChildrenCompleted");
}
void ArktsFrontend::OnLayoutChildrenCompleted(int32_t uniqueId)
{
auto iter = uniqueIdLayoutChildrenCallbacks_.find(uniqueId);
if (iter == uniqueIdLayoutChildrenCallbacks_.end()) {
return;
}
if (taskExecutor_ == nullptr) {
return;
}
auto&& observer = iter->second;
taskExecutor_->PostTask([observer] { (*observer)(); }, TaskExecutor::TaskType::JS, "ArkUIDrawChildrenCompleted");
}
bool ArktsFrontend::IsDrawChildrenCallbackFuncExist(int32_t uniqueId)
{
auto iter = uniqueIdDrawChildrenCallbacks_.find(uniqueId);
if (iter == uniqueIdDrawChildrenCallbacks_.end()) {
return false;
}
return iter->second->HasCallback();
}
bool ArktsFrontend::IsLayoutChildrenCallbackFuncExist(int32_t uniqueId)
{
auto iter = uniqueIdLayoutChildrenCallbacks_.find(uniqueId);
if (iter == uniqueIdLayoutChildrenCallbacks_.end()) {
return false;
}
return iter->second->HasCallback();
}
void ArktsFrontend::RegisterLayoutChildrenInspectorCallback(
const RefPtr<InspectorEvent>& layoutChildrenFunc, const std::string& componentId)
{
layoutChildrenCallbacks_[componentId] = layoutChildrenFunc;
}
void ArktsFrontend::RegisterLayoutInspectorCallback(const RefPtr<InspectorEvent>& layoutFunc, int32_t uniqueId)
{
uniqueIdLayoutCallbacks_[uniqueId] = layoutFunc;
}
void ArktsFrontend::RegisterDrawInspectorCallback(const RefPtr<InspectorEvent>& drawFunc, int32_t uniqueId)
{
uniqueIdDrawCallbacks_[uniqueId] = drawFunc;
}
void ArktsFrontend::RegisterDrawChildrenInspectorCallback(
const RefPtr<InspectorEvent>& drawChildrenFunc, int32_t uniqueId)
{
uniqueIdDrawChildrenCallbacks_[uniqueId] = drawChildrenFunc;
}
void ArktsFrontend::RegisterLayoutChildrenInspectorCallback(
const RefPtr<InspectorEvent>& layoutChildrenFunc, int32_t uniqueId)
{
uniqueIdLayoutChildrenCallbacks_[uniqueId] = layoutChildrenFunc;
}
void ArktsFrontend::UnregisterLayoutChildrenInspectorCallback(const std::string& componentId)
{
layoutChildrenCallbacks_.erase(componentId);
}
void ArktsFrontend::UnregisterLayoutInspectorCallback(int32_t uniqueId)
{
uniqueIdLayoutCallbacks_.erase(uniqueId);
}
void ArktsFrontend::UnregisterDrawInspectorCallback(int32_t uniqueId)
{
uniqueIdDrawCallbacks_.erase(uniqueId);
}
void ArktsFrontend::UnregisterDrawChildrenInspectorCallback(const int32_t uniqueId)
{
uniqueIdDrawChildrenCallbacks_.erase(uniqueId);
}
void ArktsFrontend::UnregisterLayoutChildrenInspectorCallback(const int32_t uniqueId)
{
uniqueIdLayoutChildrenCallbacks_.erase(uniqueId);
}
extern "C" ACE_FORCE_EXPORT void OHOS_ACE_PreloadAceArkTSModule(void* aniEnv)
{
ArktsFrontend::PreloadAceModule(aniEnv);
}
extern "C" ACE_FORCE_EXPORT void* OHOS_ACE_GetArkTSRuntime()
{
return ArktsFrontend::preloadArkTSRuntime;
}
ani_ref CreateStorageReference(void* runtime, void* storage)
{
ani_ref ref = nullptr;
if (runtime && storage) {
auto* env = reinterpret_cast<ani_env*>(runtime);
env->GlobalReference_Create(reinterpret_cast<ani_ref>(storage), &ref);
if (!ref) {
return nullptr;
}
}
return ref;
}
void DeleteStorageReference(void* runtime, void* storage)
{
if (runtime && storage) {
auto* env = reinterpret_cast<ani_env*>(runtime);
env->GlobalReference_Delete(reinterpret_cast<ani_object>(storage));
}
}
extern "C" ACE_FORCE_EXPORT Frontend* OHOS_ACE_CreateArktsFrontend(void* runtime) {
if (!runtime) {
LOGE("runtime is nullptr.");
return nullptr;
}
return static_cast<Frontend*>(new ArktsFrontend(runtime));
}
extern "C" ACE_FORCE_EXPORT void* OHOS_ACE_CreateAniReference(void* runtime, void* storage) {
if (!runtime || !storage) {
return nullptr;
}
return static_cast<void*>(CreateStorageReference(runtime, storage));
}
extern "C" ACE_FORCE_EXPORT void OHOS_ACE_DeleteAniReference(void* runtime, void* storage) {
if (!runtime || !storage) {
return;
}
DeleteStorageReference(runtime, storage);
}
}