• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
17 
18 #include "securec.h"
19 
20 #include "base/subwindow/subwindow_manager.h"
21 #include "bridge/cj_frontend/frontend/cj_frontend_loader.h"
22 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
23 #include "bridge/common/accessibility/accessibility_node_manager.h"
24 #include "core/common/font_manager.h"
25 #include "core/components/dialog/dialog_theme.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 
28 using namespace OHOS::Ace::NG;
29 using namespace OHOS::Ace;
30 
31 namespace OHOS::Ace {
32 namespace {
33 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
34 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
35 constexpr int32_t CALLBACK_ERRORCODE_CANCEL = 1;
36 constexpr int32_t CALLBACK_DATACODE_ZERO = 0;
37 
38 // helper function to run OverlayManager task
39 // ensures that the task runs in subwindow instead of main Window
MainWindowOverlay(std::function<void (RefPtr<NG::OverlayManager>)> && task,const std::string & name)40 void MainWindowOverlay(std::function<void(RefPtr<NG::OverlayManager>)>&& task, const std::string& name)
41 {
42     auto currentId = Container::CurrentId();
43     ContainerScope scope(currentId);
44     auto context = NG::PipelineContext::GetCurrentContext();
45     CHECK_NULL_VOID(context);
46     auto overlayManager = context->GetOverlayManager();
47     context->GetTaskExecutor()->PostTask(
48         [task = std::move(task), weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
49             auto overlayManager = weak.Upgrade();
50             task(overlayManager);
51         },
52         TaskExecutor::TaskType::UI, name);
53 }
54 } // namespace
55 
56 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const57 void CJFrontendAbstract::TransferJsResponseDataPreview(
58     int32_t callbackId, int32_t code, ResponseData responseData) const
59 {}
60 #endif
61 
~CJFrontendAbstract()62 CJFrontendAbstract::~CJFrontendAbstract()
63 {
64     LOGD("CJFrontendAbstract destroyed.");
65 }
66 
Initialize(FrontendType type,const RefPtr<OHOS::Ace::TaskExecutor> & taskExecutor)67 bool CJFrontendAbstract::Initialize(FrontendType type, const RefPtr<OHOS::Ace::TaskExecutor>& taskExecutor)
68 {
69     if (type != FrontendType::DECLARATIVE_CJ) {
70         LOGE("CJFrontendAbstract Initialize failed, FrontendType only accept DECLARATIVE_CJ");
71         return false;
72     }
73     LOGD("CJFrontendAbstract initialize begin.");
74     taskExecutor_ = taskExecutor;
75     manifestParser_ = AceType::MakeRefPtr<Framework::ManifestParser>();
76     accessibilityManager_ = Framework::AccessibilityNodeManager::Create();
77 
78     type_ = type;
79     InternalInitialize();
80     if (!pageRouterManager_) {
81         LOGE("InternalInitialize must initialize pageRouterManager_");
82         return false;
83     }
84     return true;
85 }
86 
FlushReload()87 void CJFrontendAbstract::FlushReload()
88 {
89     if (!Container::IsCurrentUseNewPipeline()) {
90         LOGW("not support old pipeline");
91         return;
92     }
93     pageRouterManager_->FlushReload();
94 }
95 
RebuildAllPages()96 void CJFrontendAbstract::RebuildAllPages()
97 {
98     CHECK_NULL_VOID(pageRouterManager_);
99     auto url = pageRouterManager_->GetCurrentPageUrl();
100     pageRouterManager_->Clear();
101     pageRouterManager_->RunPage(url, "");
102 }
103 
NavigatePage(uint8_t type,const PageTarget & target,const std::string & params)104 void CJFrontendAbstract::NavigatePage(uint8_t type, const PageTarget& target, const std::string& params)
105 {
106     switch (static_cast<NavigatorType>(type)) {
107         case NavigatorType::PUSH:
108             PushPage(target.url, params);
109             break;
110         case NavigatorType::REPLACE:
111             ReplacePage(target.url, params);
112             break;
113         case NavigatorType::BACK:
114             Back(target.url, params);
115             break;
116         default:
117             LOGE("Navigator type is invalid!");
118             Back(target.url, params);
119     }
120 }
121 
OnBackPressed()122 bool CJFrontendAbstract::OnBackPressed()
123 {
124     return pageRouterManager_->PopWithExitCheck();
125 }
126 
OnShow()127 void CJFrontendAbstract::OnShow()
128 {
129     foregroundFrontend_ = true;
130     pageRouterManager_->OnShowCurrent();
131 }
132 
OnHide()133 void CJFrontendAbstract::OnHide()
134 {
135     foregroundFrontend_ = false;
136     pageRouterManager_->OnHideCurrent();
137 }
138 
Destroy()139 void CJFrontendAbstract::Destroy()
140 {
141     LOGD("CJFrontendAbstract Destroy begin.");
142 }
143 
CheckLoadAppLibrary()144 bool CJFrontendAbstract::CheckLoadAppLibrary()
145 {
146     return Framework::CJRuntimeDelegate::GetInstance()->CheckLoadCJLibrary();
147 }
148 
AttachPipelineContext(const RefPtr<PipelineBase> & context)149 void CJFrontendAbstract::AttachPipelineContext(const RefPtr<PipelineBase>& context)
150 {
151     pipelineContextHolder_.Attach(context);
152     auto jsAccessibility = AceType::DynamicCast<Framework::AccessibilityNodeManager>(accessibilityManager_);
153     jsAccessibility->SetPipelineContext(context);
154     jsAccessibility->InitializeCallback();
155 }
156 
SetAssetManager(const RefPtr<AssetManager> & assetManager)157 void CJFrontendAbstract::SetAssetManager(const RefPtr<AssetManager>& assetManager)
158 {
159     assetManager_ = assetManager;
160 }
161 
RunPage(const std::string & url,const std::string & params)162 UIContentErrorCode CJFrontendAbstract::RunPage(const std::string& url, const std::string& params)
163 {
164     LOGI("CJFrontendAbstract::RunPage start: %{public}s", url.c_str());
165     if (!isStageModel_) {
166         if (!CheckLoadAppLibrary()) {
167             TAG_LOGW(AceLogTag::ACE_FORM, "fail to run page due to path url is empty");
168             return UIContentErrorCode::NULL_URL;
169         }
170     }
171     InternalRunPage(url, params);
172     return UIContentErrorCode::NO_ERRORS;
173 }
174 
ReplacePage(const std::string & url,const std::string & params)175 void CJFrontendAbstract::ReplacePage(const std::string& url, const std::string& params)
176 {
177     pageRouterManager_->Replace({ url }, params);
178 }
179 
PushPage(const std::string & url,const std::string & params)180 void CJFrontendAbstract::PushPage(const std::string& url, const std::string& params)
181 {
182     pageRouterManager_->Push({ url }, params);
183 }
184 
Back(const std::string & uri,const std::string & params)185 void CJFrontendAbstract::Back(const std::string& uri, const std::string& params)
186 {
187     pageRouterManager_->BackWithTarget({ uri }, params);
188 }
189 
CallRouterBack()190 void CJFrontendAbstract::CallRouterBack()
191 {
192     pageRouterManager_->Pop();
193 }
194 
InternalRunPage(const std::string & url,const std::string & params)195 void CJFrontendAbstract::InternalRunPage(const std::string& url, const std::string& params)
196 {
197     LOGI("InternalRunPage %{public}s", url.c_str());
198     taskExecutor_->PostTask(
199         [pageRouterManager = pageRouterManager_, url, params] { pageRouterManager->RunPage(url, params); },
200         TaskExecutor::TaskType::UI, "CJFrontendInternalRunPage");
201 }
202 
MeasureText(const MeasureContext & context)203 double CJFrontendAbstract::MeasureText(const MeasureContext& context)
204 {
205     return MeasureUtil::MeasureText(context);
206 }
207 
MeasureTextSize(const MeasureContext & context)208 Size CJFrontendAbstract::MeasureTextSize(const MeasureContext& context)
209 {
210     LOGI("CJFrontendAbstract::MeasureTextSize start");
211     return MeasureUtil::MeasureTextSize(context);
212 }
213 
ShowToast(const std::string & message,int32_t duration,const std::string & bottom,const NG::ToastShowMode & showMode)214 void CJFrontendAbstract::ShowToast(
215     const std::string& message, int32_t duration, const std::string& bottom, const NG::ToastShowMode& showMode)
216 {
217     int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
218     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
219     auto task = [durationTime, message, bottom, isRightToLeft, showMode, containerId = Container::CurrentId()](
220                     const RefPtr<NG::OverlayManager>& overlayManager) {
221         CHECK_NULL_VOID(overlayManager);
222         ContainerScope scope(containerId);
223         auto toastInfo = NG::ToastInfo { .message = message,
224             .duration = durationTime,
225             .bottom = bottom,
226             .isRightToLeft = isRightToLeft,
227             .showMode = showMode,
228             .alignment = -1,
229             .offset = std::nullopt };
230         overlayManager->ShowToast(toastInfo, nullptr);
231     };
232     MainWindowOverlay(std::move(task), "ArkUIOverlayShowToast");
233 }
234 
ShowDialog(const std::string & title,const std::string & message,const std::vector<ButtonInfo> & buttons,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)235 void CJFrontendAbstract::ShowDialog(const std::string& title, const std::string& message,
236     const std::vector<ButtonInfo>& buttons, std::function<void(int32_t, int32_t)>&& callback,
237     const std::set<std::string>& callbacks)
238 {
239     DialogProperties dialogProperties = { .title = title, .content = message, .buttons = buttons };
240     ShowDialogInner(dialogProperties, std::move(callback), callbacks);
241 }
242 
Replace(const std::string & url,const std::string & params,CJPageRouterAbstract::RouterMode modeValue)243 void CJFrontendAbstract::Replace(const std::string& url, const std::string& params,
244     CJPageRouterAbstract::RouterMode modeValue)
245 {
246     pageRouterManager_->Replace({ url }, params, modeValue);
247 }
248 
ShowDialogInner(DialogProperties & dialogProperties,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)249 void CJFrontendAbstract::ShowDialogInner(DialogProperties& dialogProperties,
250     std::function<void(int32_t, int32_t)>&& callback, const std::set<std::string>& callbacks)
251 {
252     auto pipelineContext = pipelineContextHolder_.Get();
253     LOGI("Dialog IsCurrentUseNewPipeline.");
254     dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
255         taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
256             TaskExecutor::TaskType::JS, "CJFroentendShowDialogInner");
257     };
258     dialogProperties.onSuccess = std::move(callback);
259     auto task = [dialogProperties](const RefPtr<NG::OverlayManager>& overlayManager) {
260         CHECK_NULL_VOID(overlayManager);
261         RefPtr<NG::FrameNode> dialog;
262         LOGI("Begin to show dialog ");
263         if (dialogProperties.isShowInSubWindow) {
264             dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
265             CHECK_NULL_VOID(dialog);
266             if (dialogProperties.isModal) {
267                 DialogProperties maskarg;
268                 maskarg.isMask = true;
269                 maskarg.autoCancel = dialogProperties.autoCancel;
270                 auto mask = overlayManager->ShowDialog(maskarg, nullptr, false);
271                 CHECK_NULL_VOID(mask);
272                 overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
273             }
274         } else {
275             dialog = overlayManager->ShowDialog(
276                 dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
277             CHECK_NULL_VOID(dialog);
278         }
279     };
280     MainWindowOverlay(std::move(task), "ArkUIShowDialogInner");
281 }
282 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)283 void CJFrontendAbstract::ShowActionMenu(
284     const std::string& title, const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
285 {
286     DialogProperties dialogProperties = {
287         .title = title,
288         .autoCancel = true,
289         .isMenu = true,
290         .buttons = button,
291     };
292     ShowActionMenuInner(dialogProperties, button, std::move(callback));
293 }
294 
ShowActionMenuInner(DialogProperties & dialogProperties,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)295 void CJFrontendAbstract::ShowActionMenuInner(DialogProperties& dialogProperties, const std::vector<ButtonInfo>& button,
296     std::function<void(int32_t, int32_t)>&& callback)
297 {
298     auto pipeline = PipelineBase::GetCurrentContext();
299     CHECK_NULL_VOID(pipeline);
300     auto theme = pipeline->GetTheme<DialogTheme>();
301     CHECK_NULL_VOID(theme);
302     ButtonInfo buttonInfo = { .text = theme->GetCancelText(), .textColor = "" };
303     dialogProperties.buttons.emplace_back(buttonInfo);
304     dialogProperties.onCancel = [callback, taskExecutor = taskExecutor_] {
305         taskExecutor->PostTask([callback]() { callback(CALLBACK_ERRORCODE_CANCEL, CALLBACK_DATACODE_ZERO); },
306             TaskExecutor::TaskType::JS, "CJFroentendShowActionMenuInnerOnCancel");
307     };
308     dialogProperties.onSuccess = std::move(callback);
309     auto context = DynamicCast<NG::PipelineContext>(pipelineContextHolder_.Get());
310     auto overlayManager = context ? context->GetOverlayManager() : nullptr;
311     taskExecutor_->PostTask(
312         [dialogProperties, weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
313             auto overlayManager = weak.Upgrade();
314             CHECK_NULL_VOID(overlayManager);
315             RefPtr<NG::FrameNode> dialog;
316             if (dialogProperties.isShowInSubWindow) {
317                 dialog = SubwindowManager::GetInstance()->ShowDialogNG(dialogProperties, nullptr);
318                 CHECK_NULL_VOID(dialog);
319                 if (dialogProperties.isModal) {
320                     DialogProperties maskarg;
321                     maskarg.autoCancel = dialogProperties.autoCancel;
322                     maskarg.isMask = true;
323                     auto mask = overlayManager->ShowDialog(maskarg, nullptr, false);
324                     CHECK_NULL_VOID(mask);
325                     overlayManager->SetMaskNodeId(dialog->GetId(), mask->GetId());
326                 }
327             } else {
328                 dialog = overlayManager->ShowDialog(
329                     dialogProperties, nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
330                 CHECK_NULL_VOID(dialog);
331             }
332         },
333         TaskExecutor::TaskType::UI, "CJFroentendShowActionMenuInner");
334 }
335 
OpenCustomDialog(const PromptDialogAttr & dialogAttr,std::function<void (int32_t)> && callback)336 void CJFrontendAbstract::OpenCustomDialog(const PromptDialogAttr& dialogAttr, std::function<void(int32_t)>&& callback)
337 {
338     DialogProperties dialogProperties = { .onWillDismiss = dialogAttr.customOnWillDismiss,
339         .isShowInSubWindow = dialogAttr.showInSubWindow,
340         .isModal = dialogAttr.isModal,
341         .isSysBlurStyle = false,
342         .customBuilder = dialogAttr.customBuilder,
343         .maskRect = dialogAttr.maskRect };
344 #if defined(PREVIEW)
345     if (dialogProperties.isShowInSubWindow) {
346         LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
347              "emulator or a real device instead.");
348         dialogProperties.isShowInSubWindow = false;
349     }
350 #endif
351     if (dialogAttr.alignment.has_value()) {
352         dialogProperties.alignment = dialogAttr.alignment.value();
353     }
354     if (dialogAttr.offset.has_value()) {
355         dialogProperties.offset = dialogAttr.offset.value();
356     }
357     if (!Container::IsCurrentUseNewPipeline()) {
358         LOGW("not support old pipeline");
359         return;
360     }
361     LOGI("Dialog IsCurrentUseNewPipeline.");
362     auto task = [dialogAttr, dialogProperties, callback](const RefPtr<NG::OverlayManager>& overlayManager) mutable {
363         CHECK_NULL_VOID(overlayManager);
364         LOGI("Begin to open custom dialog ");
365         if (dialogProperties.isShowInSubWindow) {
366             SubwindowManager::GetInstance()->OpenCustomDialogNG(dialogProperties, std::move(callback));
367             if (dialogProperties.isModal) {
368                 LOGW("temporary not support isShowInSubWindow and isModal");
369             }
370         } else {
371             overlayManager->OpenCustomDialog(dialogProperties, std::move(callback));
372         }
373     };
374     MainWindowOverlay(std::move(task), "ArkUIOpenCustomDialog");
375     return;
376 }
377 
CloseCustomDialog(int32_t id)378 void CJFrontendAbstract::CloseCustomDialog(int32_t id)
379 {
380     auto task = [id](const RefPtr<NG::OverlayManager>& overlayManager) {
381         CHECK_NULL_VOID(overlayManager);
382         LOGI("begin to close custom dialog.");
383         overlayManager->CloseCustomDialog(id);
384         SubwindowManager::GetInstance()->CloseCustomDialogNG(id);
385     };
386     MainWindowOverlay(std::move(task), "ArkUICloseCustomDialog");
387     return;
388 }
389 
RegisterFont(const std::string & familyName,const std::string & familySrc,const std::string & bundleName,const std::string & moduleName)390 void CJFrontendAbstract::RegisterFont(const std::string& familyName, const std::string& familySrc,
391     const std::string& bundleName, const std::string& moduleName)
392 {
393     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc, bundleName, moduleName);
394 }
395 
GetSystemFontList()396 VectorStringHandle CJFrontendAbstract::GetSystemFontList()
397 {
398     auto fontList = new std::vector<std::string>;
399     pipelineContextHolder_.Get()->GetSystemFontList(*fontList);
400     return fontList;
401 }
402 
GetSystemFont(const std::string & fontName)403 NativeOptionFontInfo CJFrontendAbstract::GetSystemFont(const std::string& fontName)
404 {
405     FontInfo fontInfo;
406     if (!pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo)) {
407         return NativeOptionFontInfo { .hasValue = false, .info = nullptr };
408     }
409     return NativeOptionFontInfo { .hasValue = true,
410         .info = new NativeFontInfo { .path = fontInfo.path.c_str(),
411             .postScriptName = fontInfo.postScriptName.c_str(),
412             .fullName = fontInfo.fullName.c_str(),
413             .family = fontInfo.family.c_str(),
414             .subfamily = fontInfo.subfamily.c_str(),
415             .weight = fontInfo.weight,
416             .width = fontInfo.width,
417             .italic = fontInfo.italic,
418             .monoSpace = fontInfo.monoSpace,
419             .symbolic = fontInfo.symbolic } };
420 }
BackIndex(int32_t index,const std::string & params)421 void CJFrontendAbstract::BackIndex(int32_t index, const std::string& params)
422 {
423     pageRouterManager_->BackWithIndex(index, params);
424 }
425 
Clear()426 void CJFrontendAbstract::Clear()
427 {
428     pageRouterManager_->Clear();
429 }
430 
GetLength()431 int32_t CJFrontendAbstract::GetLength()
432 {
433     return pageRouterManager_->GetStackSize();
434 }
435 
SetShowAlertBeforeBackPage(const char * msg,std::function<void (int32_t)> && callback)436 void CJFrontendAbstract::SetShowAlertBeforeBackPage(const char* msg, std::function<void(int32_t)>&& callback)
437 {
438     pageRouterManager_->EnableAlertBeforeBackPage(msg, callback);
439 }
440 
SetHideAlertBeforeBackPage()441 void CJFrontendAbstract::SetHideAlertBeforeBackPage()
442 {
443     pageRouterManager_->DisableAlertBeforeBackPage();
444 }
445 
CopyStr(const std::string & str)446 static char* CopyStr(const std::string& str)
447 {
448     char* newStr = new (std::nothrow) char[str.length() + 1];
449     if (newStr == nullptr) {
450         return nullptr;
451     }
452 
453     int err = strcpy_s(newStr, str.length() + 1, str.c_str());
454     if (err != 0) {
455         delete[] newStr;
456         return nullptr;
457     }
458 
459     return newStr;
460 }
461 
GetState(CJPageRouterAbstract::RouterState * info)462 void CJFrontendAbstract::GetState(CJPageRouterAbstract::RouterState* info)
463 {
464     std::string name_str = "";
465     std::string path_str = "";
466     std::string params_str = "";
467     pageRouterManager_->GetState(info->index, name_str, path_str, params_str);
468     info->name = CopyStr(name_str);
469     info->path = CopyStr(path_str);
470     info->params = CopyStr(params_str);
471 }
472 
GetStateByIndex(CJPageRouterAbstract::RouterState * info)473 void CJFrontendAbstract::GetStateByIndex(CJPageRouterAbstract::RouterState* info)
474 {
475     std::string name_str = "";
476     std::string path_str = "";
477     std::string params_str = "";
478     pageRouterManager_->GetStateByIndex(info->index, name_str, path_str, params_str);
479     info->name = CopyStr(name_str);
480     info->path = CopyStr(path_str);
481     info->params = CopyStr(params_str);
482 }
483 
GetStateByUrl(const char * url)484 CJPageRouterAbstract::RouterStateList CJFrontendAbstract::GetStateByUrl(const char* url)
485 {
486     CJPageRouterAbstract::RouterStateList result;
487     std::vector<CJPageRouterAbstract::RouterState> states = pageRouterManager_->GetStateByUrl(url);
488     if (states.empty()) {
489         return result;
490     }
491     auto stateslist = new CJPageRouterAbstract::RouterState[states.size()];
492     size_t idx = 0;
493     for (auto state : states) {
494         stateslist[idx].index = state.index;
495         stateslist[idx].name = state.name;
496         stateslist[idx].path = state.path;
497         stateslist[idx].params = state.params;
498         idx++;
499     }
500     result.array = stateslist;
501     result.size = static_cast<int64_t>(states.size());
502     result.free = CJPageRouterAbstract::RouterStateListFree;
503     return result;
504 }
PushPageWithCallback(const std::string & url,const std::string & params,CJPageRouterAbstract::RouterMode & mode,std::function<void (int32_t)> && callback)505 void CJFrontendAbstract::PushPageWithCallback(const std::string& url, const std::string& params,
506     CJPageRouterAbstract::RouterMode& mode, std::function<void(int32_t)>&& callback)
507 {
508     pageRouterManager_->PushPageWithCallback({ url, mode, "", callback }, params);
509 }
510 
ReplacePageWithCallback(const std::string & url,const std::string & params,CJPageRouterAbstract::RouterMode & mode,std::function<void (int32_t)> && callback)511 void CJFrontendAbstract::ReplacePageWithCallback(const std::string& url, const std::string& params,
512     CJPageRouterAbstract::RouterMode& mode, std::function<void(int32_t)>&& callback)
513 {
514     pageRouterManager_->ReplacePageWithCallback({ url, mode, "", callback }, params);
515 }
516 
517 } // namespace OHOS::Ace
518