1 /*
2 * Copyright (c) 2022 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 "frameworks/bridge/declarative_frontend/ng/declarative_frontend_ng.h"
17
18 #include "base/log/dump_log.h"
19 #include "core/common/recorder/node_data_cache.h"
20 #include "core/common/thread_checker.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 #include "frameworks/bridge/declarative_frontend/ng/page_router_manager_factory.h"
23
24 namespace OHOS::Ace {
25
~DeclarativeFrontendNG()26 DeclarativeFrontendNG::~DeclarativeFrontendNG() noexcept
27 {
28 LOG_DESTROY();
29 }
30
Destroy()31 void DeclarativeFrontendNG::Destroy()
32 {
33 // The call doesn't change the page pop status
34 Recorder::NodeDataCache::Get().OnBeforePagePop(true);
35 CHECK_RUN_ON(JS);
36 // To guarantee the jsEngine_ and delegate_ released in js thread
37 delegate_.Reset();
38 jsEngine_->Destroy();
39 jsEngine_.Reset();
40 }
41
Initialize(FrontendType type,const RefPtr<TaskExecutor> & taskExecutor)42 bool DeclarativeFrontendNG::Initialize(FrontendType type, const RefPtr<TaskExecutor>& taskExecutor)
43 {
44 type_ = type;
45 taskExecutor_ = taskExecutor;
46 ACE_DCHECK(type_ == FrontendType::DECLARATIVE_JS);
47 InitializeDelegate(taskExecutor);
48 bool needPostJsTask = true;
49 auto container = Container::Current();
50 if (container) {
51 const auto& setting = container->GetSettings();
52 needPostJsTask = !(setting.usePlatformAsUIThread && setting.useUIAsJSThread);
53 }
54 auto initJSEngineTask = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_), delegate = delegate_] {
55 auto jsEngine = weakEngine.Upgrade();
56 if (!jsEngine) {
57 return;
58 }
59 jsEngine->Initialize(delegate);
60 };
61 if (needPostJsTask) {
62 taskExecutor->PostTask(initJSEngineTask, TaskExecutor::TaskType::JS, "ArkUIInitJsEngine");
63 } else {
64 initJSEngineTask();
65 }
66 return true;
67 }
68
AttachPipelineContext(const RefPtr<PipelineBase> & context)69 void DeclarativeFrontendNG::AttachPipelineContext(const RefPtr<PipelineBase>& context)
70 {
71 if (delegate_) {
72 delegate_->AttachPipelineContext(context);
73 }
74 }
75
AttachSubPipelineContext(const RefPtr<PipelineBase> & context)76 void DeclarativeFrontendNG::AttachSubPipelineContext(const RefPtr<PipelineBase>& context)
77 {
78 if (!delegate_) {
79 return;
80 }
81 delegate_->AttachSubPipelineContext(context);
82 }
83
SetAssetManager(const RefPtr<AssetManager> & assetManager)84 void DeclarativeFrontendNG::SetAssetManager(const RefPtr<AssetManager>& assetManager)
85 {
86 if (delegate_) {
87 delegate_->SetAssetManager(assetManager);
88 }
89 }
90
InitializeDelegate(const RefPtr<TaskExecutor> & taskExecutor)91 void DeclarativeFrontendNG::InitializeDelegate(const RefPtr<TaskExecutor>& taskExecutor)
92 {
93 auto pageRouterManager = NG::PageRouterManagerFactory::CreateManager();
94 auto loadPageCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](const std::string& url,
95 const std::function<void(const std::string&, int32_t)>& errorCallback) {
96 auto jsEngine = weakEngine.Upgrade();
97 if (!jsEngine) {
98 return false;
99 }
100 return jsEngine->LoadPageSource(url, errorCallback);
101 };
102
103 auto loadPageByBufferCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
104 const std::shared_ptr<std::vector<uint8_t>>& content,
105 const std::function<void(const std::string&, int32_t)>& errorCallback,
106 const std::string& contentName) {
107 auto jsEngine = weakEngine.Upgrade();
108 if (!jsEngine) {
109 return false;
110 }
111 return jsEngine->LoadPageSource(content, errorCallback, contentName);
112 };
113
114 auto mediaQueryCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
115 const std::string& callbackId, const std::string& args) {
116 auto jsEngine = weakEngine.Upgrade();
117 if (!jsEngine) {
118 return;
119 }
120 jsEngine->MediaQueryCallback(callbackId, args);
121 };
122
123 auto layoutInspectorCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
124 const std::string& componentId) {
125 auto jsEngine = weakEngine.Upgrade();
126 if (!jsEngine) {
127 return;
128 }
129 jsEngine->LayoutInspectorCallback(componentId);
130 };
131
132 auto drawInspectorCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
133 const std::string& componentId) {
134 auto jsEngine = weakEngine.Upgrade();
135 if (!jsEngine) {
136 return;
137 }
138 jsEngine->DrawInspectorCallback(componentId);
139 };
140
141 auto onStartContinuationCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() -> bool {
142 auto jsEngine = weakEngine.Upgrade();
143 if (!jsEngine) {
144 return false;
145 }
146 return jsEngine->OnStartContinuation();
147 };
148
149 auto onCompleteContinuationCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](int32_t code) {
150 auto jsEngine = weakEngine.Upgrade();
151 if (!jsEngine) {
152 return;
153 }
154 jsEngine->OnCompleteContinuation(code);
155 };
156
157 auto onSaveDataCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](std::string& savedData) {
158 auto jsEngine = weakEngine.Upgrade();
159 if (!jsEngine) {
160 return;
161 }
162 jsEngine->OnSaveData(savedData);
163 };
164
165 auto onRemoteTerminatedCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() {
166 auto jsEngine = weakEngine.Upgrade();
167 if (!jsEngine) {
168 return;
169 }
170 jsEngine->OnRemoteTerminated();
171 };
172
173 auto onRestoreDataCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
174 const std::string& data) -> bool {
175 auto jsEngine = weakEngine.Upgrade();
176 if (!jsEngine) {
177 return false;
178 }
179 return jsEngine->OnRestoreData(data);
180 };
181
182 auto destroyApplicationCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
183 const std::string& packageName) {
184 auto jsEngine = weakEngine.Upgrade();
185 if (!jsEngine) {
186 return;
187 }
188 jsEngine->DestroyApplication(packageName);
189 };
190
191 auto updateApplicationStateCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
192 const std::string& packageName, Frontend::State state) {
193 auto jsEngine = weakEngine.Upgrade();
194 if (!jsEngine) {
195 return;
196 }
197 jsEngine->UpdateApplicationState(packageName, state);
198 };
199
200 auto onWindowDisplayModeChangedCallBack = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
201 bool isShownInMultiWindow, const std::string& data) {
202 auto jsEngine = weakEngine.Upgrade();
203 if (!jsEngine) {
204 return;
205 }
206 jsEngine->OnWindowDisplayModeChanged(isShownInMultiWindow, data);
207 };
208
209 auto externalEventCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
210 const std::string& componentId, const uint32_t nodeId,
211 const bool isDestroy) {
212 auto jsEngine = weakEngine.Upgrade();
213 if (!jsEngine) {
214 return;
215 }
216 jsEngine->FireExternalEvent(componentId, nodeId, isDestroy);
217 };
218
219 auto timerCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
220 const std::string& callbackId, const std::string& delay, bool isInterval) {
221 auto jsEngine = weakEngine.Upgrade();
222 if (!jsEngine) {
223 return;
224 }
225 jsEngine->TimerCallback(callbackId, delay, isInterval);
226 };
227
228 auto loadNamedRouterCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)](
229 const std::string& namedRouter, bool isTriggeredByJs) {
230 auto jsEngine = weakEngine.Upgrade();
231 if (!jsEngine) {
232 return false;
233 }
234 return jsEngine->LoadNamedRouterSource(namedRouter, isTriggeredByJs);
235 };
236
237 auto updateRootComponentCallback = [weakEngine = WeakPtr<Framework::JsEngine>(jsEngine_)]() {
238 auto jsEngine = weakEngine.Upgrade();
239 if (!jsEngine) {
240 return false;
241 }
242 return jsEngine->UpdateRootComponent();
243 };
244
245 pageRouterManager->SetLoadJsCallback(std::move(loadPageCallback));
246 pageRouterManager->SetLoadJsByBufferCallback(std::move(loadPageByBufferCallback));
247 pageRouterManager->SetLoadNamedRouterCallback(std::move(loadNamedRouterCallback));
248 pageRouterManager->SetUpdateRootComponentCallback(std::move(updateRootComponentCallback));
249
250 delegate_ = AceType::MakeRefPtr<Framework::FrontendDelegateDeclarativeNG>(taskExecutor);
251 delegate_->SetMediaQueryCallback(std::move(mediaQueryCallback));
252 delegate_->SetLayoutInspectorCallback(std::move(layoutInspectorCallback));
253 delegate_->SetDrawInspectorCallback(std::move(drawInspectorCallback));
254 delegate_->SetOnStartContinuationCallBack(std::move(onStartContinuationCallBack));
255 delegate_->SetOnCompleteContinuationCallBack(std::move(onCompleteContinuationCallBack));
256 delegate_->SetOnSaveDataCallBack(std::move(onSaveDataCallBack));
257 delegate_->SetOnRemoteTerminatedCallBack(std::move(onRemoteTerminatedCallBack));
258 delegate_->SetOnRestoreDataCallBack(std::move(onRestoreDataCallBack));
259 delegate_->SetDestroyApplicationCallback(std::move(destroyApplicationCallback));
260 delegate_->SetUpdateApplicationStateCallback(std::move(updateApplicationStateCallback));
261 delegate_->SetOnWindowDisplayModeChangedCallback(std::move(onWindowDisplayModeChangedCallBack));
262 delegate_->SetExternalEventCallback(std::move(externalEventCallback));
263 delegate_->SetTimerCallback(std::move(timerCallback));
264
265 delegate_->SetPageRouterManager(pageRouterManager);
266 if (jsEngine_) {
267 delegate_->SetGroupJsBridge(jsEngine_->GetGroupJsBridge());
268 }
269 }
270
GetPageRouterManager() const271 RefPtr<NG::PageRouterManager> DeclarativeFrontendNG::GetPageRouterManager() const
272 {
273 CHECK_NULL_RETURN(delegate_, nullptr);
274 return delegate_->GetPageRouterManager();
275 }
276
UpdateState(Frontend::State state)277 void DeclarativeFrontendNG::UpdateState(Frontend::State state)
278 {
279 if (!delegate_ || state == Frontend::State::ON_CREATE) {
280 return;
281 }
282 bool needPostJsTask = true;
283 auto container = Container::Current();
284 CHECK_NULL_VOID(container);
285 const auto& setting = container->GetSettings();
286 needPostJsTask = !(setting.usePlatformAsUIThread && setting.useUIAsJSThread);
287 if (needPostJsTask) {
288 delegate_->UpdateApplicationState(delegate_->GetAppID(), state);
289 return;
290 }
291 if (jsEngine_) {
292 jsEngine_->UpdateApplicationState(delegate_->GetAppID(), state);
293 }
294 }
295
OnConfigurationUpdated(const std::string & data)296 void DeclarativeFrontendNG::OnConfigurationUpdated(const std::string& data)
297 {
298 if (delegate_) {
299 delegate_->OnConfigurationUpdated(data);
300 }
301 }
302
OnActive()303 void DeclarativeFrontendNG::OnActive()
304 {
305 if (delegate_) {
306 foregroundFrontend_ = true;
307 delegate_->InitializeAccessibilityCallback();
308 }
309 }
310
OnCompleteContinuation(int32_t code)311 void DeclarativeFrontendNG::OnCompleteContinuation(int32_t code)
312 {
313 if (delegate_) {
314 delegate_->OnCompleteContinuation(code);
315 }
316 }
317
OnSaveData(std::string & data)318 void DeclarativeFrontendNG::OnSaveData(std::string& data)
319 {
320 if (delegate_) {
321 delegate_->OnSaveData(data);
322 }
323 }
324
OnRemoteTerminated()325 void DeclarativeFrontendNG::OnRemoteTerminated()
326 {
327 if (delegate_) {
328 delegate_->OnRemoteTerminated();
329 }
330 }
331
NotifyAppStorage(const std::string & key,const std::string & value)332 void DeclarativeFrontendNG::NotifyAppStorage(const std::string& key, const std::string& value)
333 {
334 if (!delegate_) {
335 return;
336 }
337 delegate_->NotifyAppStorage(jsEngine_, key, value);
338 }
339
GetRouterSize() const340 int32_t DeclarativeFrontendNG::GetRouterSize() const
341 {
342 if (delegate_) {
343 return delegate_->GetStackSize();
344 }
345 return -1;
346 }
347
OnStartContinuation()348 bool DeclarativeFrontendNG::OnStartContinuation()
349 {
350 if (!delegate_) {
351 return false;
352 }
353 return delegate_->OnStartContinuation();
354 }
355
OnRestoreData(const std::string & data)356 bool DeclarativeFrontendNG::OnRestoreData(const std::string& data)
357 {
358 if (!delegate_) {
359 return false;
360 }
361 return delegate_->OnRestoreData(data);
362 }
363
RunPage(const std::string & url,const std::string & params)364 UIContentErrorCode DeclarativeFrontendNG::RunPage(const std::string& url, const std::string& params)
365 {
366 auto container = Container::Current();
367 auto isStageModel = container ? container->IsUseStageModel() : false;
368 if (!isStageModel) {
369 // In NG structure and fa mode, first load app.js
370 auto taskExecutor = container ? container->GetTaskExecutor() : nullptr;
371 CHECK_NULL_RETURN(taskExecutor, UIContentErrorCode::NULL_POINTER);
372 taskExecutor->PostTask(
373 [weak = AceType::WeakClaim(this)]() {
374 auto frontend = weak.Upgrade();
375 CHECK_NULL_VOID(frontend);
376 CHECK_NULL_VOID(frontend->jsEngine_);
377 frontend->jsEngine_->LoadFaAppSource();
378 },
379 TaskExecutor::TaskType::JS, "ArkUILoadFaAppSource");
380 }
381 // Not use this pageId from backend, manage it in FrontendDelegateDeclarativeNg.
382 if (delegate_) {
383 delegate_->RunPage(url, params, pageProfile_);
384 return UIContentErrorCode::NO_ERRORS;
385 }
386
387 return UIContentErrorCode::NULL_POINTER;
388 }
389
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)390 UIContentErrorCode DeclarativeFrontendNG::RunPage(
391 const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
392 {
393 auto container = Container::Current();
394 auto isStageModel = container ? container->IsUseStageModel() : false;
395 if (!isStageModel) {
396 LOGE("RunPage by buffer must be run under stage model.");
397 return UIContentErrorCode::NO_STAGE;
398 }
399
400 if (delegate_) {
401 delegate_->RunPage(content, params, pageProfile_);
402 return UIContentErrorCode::NO_ERRORS;
403 }
404
405 return UIContentErrorCode::NULL_POINTER;
406 }
407
RunPageByNamedRouter(const std::string & name,const std::string & params)408 UIContentErrorCode DeclarativeFrontendNG::RunPageByNamedRouter(const std::string& name, const std::string& params)
409 {
410 if (delegate_) {
411 delegate_->RunPage(name, params, pageProfile_, true);
412 return UIContentErrorCode::NO_ERRORS;
413 }
414 return UIContentErrorCode::NULL_POINTER;
415 }
416
ReplacePage(const std::string & url,const std::string & params)417 void DeclarativeFrontendNG::ReplacePage(const std::string& url, const std::string& params)
418 {
419 if (delegate_) {
420 delegate_->Replace(url, params);
421 }
422 }
423
PushPage(const std::string & url,const std::string & params)424 void DeclarativeFrontendNG::PushPage(const std::string& url, const std::string& params)
425 {
426 if (delegate_) {
427 delegate_->Push(url, params);
428 }
429 }
430
431
GetContextValue()432 napi_value DeclarativeFrontendNG::GetContextValue()
433 {
434 return jsEngine_->GetContextValue();
435 }
436
GetFrameNodeValueByNodeId(int32_t nodeId)437 napi_value DeclarativeFrontendNG::GetFrameNodeValueByNodeId(int32_t nodeId)
438 {
439 return jsEngine_->GetFrameNodeValueByNodeId(nodeId);
440 }
441
NavigatePage(uint8_t type,const PageTarget & target,const std::string & params)442 void DeclarativeFrontendNG::NavigatePage(uint8_t type, const PageTarget& target, const std::string& params)
443 {
444 if (delegate_) {
445 delegate_->NavigatePage(type, target, params);
446 }
447 }
448
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)449 void DeclarativeFrontendNG::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
450 {
451 delegate_->OnWindowDisplayModeChanged(isShownInMultiWindow, data);
452 }
453
GetAccessibilityManager() const454 RefPtr<AccessibilityManager> DeclarativeFrontendNG::GetAccessibilityManager() const
455 {
456 if (!delegate_) {
457 return nullptr;
458 }
459 return delegate_->GetJSAccessibilityManager();
460 }
461
GetWindowConfig()462 WindowConfig& DeclarativeFrontendNG::GetWindowConfig()
463 {
464 if (!delegate_) {
465 static WindowConfig windowConfig;
466 return windowConfig;
467 }
468 return delegate_->GetWindowConfig();
469 }
470
OnBackPressed()471 bool DeclarativeFrontendNG::OnBackPressed()
472 {
473 CHECK_NULL_RETURN(delegate_, false);
474 return delegate_->OnPageBackPress();
475 }
476
OnShow()477 void DeclarativeFrontendNG::OnShow()
478 {
479 foregroundFrontend_ = true;
480 CHECK_NULL_VOID(delegate_);
481 delegate_->OnPageShow();
482 }
483
OnHide()484 void DeclarativeFrontendNG::OnHide()
485 {
486 foregroundFrontend_ = false;
487 CHECK_NULL_VOID(delegate_);
488 delegate_->OnPageHide();
489 }
490
CallRouterBack()491 void DeclarativeFrontendNG::CallRouterBack()
492 {
493 if (delegate_) {
494 if (delegate_->GetStackSize() == 1 && isSubWindow_) {
495 LOGW("Can't back because this is the last page of sub window!");
496 return;
497 }
498 delegate_->Back("", "");
499 }
500 }
501
OnSurfaceChanged(int32_t width,int32_t height)502 void DeclarativeFrontendNG::OnSurfaceChanged(int32_t width, int32_t height)
503 {
504 // TODO: update media query infos
505 if (delegate_) {
506 delegate_->OnSurfaceChanged();
507 }
508 }
509
OnLayoutCompleted(const std::string & componentId)510 void DeclarativeFrontendNG::OnLayoutCompleted(const std::string& componentId)
511 {
512 if (delegate_) {
513 delegate_->OnLayoutCompleted(componentId);
514 }
515 }
516
OnDrawCompleted(const std::string & componentId)517 void DeclarativeFrontendNG::OnDrawCompleted(const std::string& componentId)
518 {
519 if (delegate_) {
520 delegate_->OnDrawCompleted(componentId);
521 }
522 }
523
DumpFrontend() const524 void DeclarativeFrontendNG::DumpFrontend() const
525 {
526 if (!delegate_) {
527 return;
528 }
529 int32_t routerIndex = 0;
530 std::string routerName;
531 std::string routerPath;
532 delegate_->GetState(routerIndex, routerName, routerPath);
533
534 if (DumpLog::GetInstance().GetDumpFile()) {
535 DumpLog::GetInstance().AddDesc("Components: " + std::to_string(delegate_->GetComponentsCount()));
536 DumpLog::GetInstance().AddDesc("Path: " + routerPath);
537 DumpLog::GetInstance().AddDesc("Length: " + std::to_string(routerIndex));
538 DumpLog::GetInstance().Print(0, routerName, 0);
539 }
540 }
541
GetPagePath() const542 std::string DeclarativeFrontendNG::GetPagePath() const
543 {
544 if (!delegate_) {
545 return "";
546 }
547 int32_t routerIndex = 0;
548 std::string routerName;
549 std::string routerPath;
550 delegate_->GetState(routerIndex, routerName, routerPath);
551 return routerPath + routerName;
552 }
553
TriggerGarbageCollection()554 void DeclarativeFrontendNG::TriggerGarbageCollection()
555 {
556 if (jsEngine_) {
557 jsEngine_->RunGarbageCollection();
558 }
559 }
560
DumpHeapSnapshot(bool isPrivate)561 void DeclarativeFrontendNG::DumpHeapSnapshot(bool isPrivate)
562 {
563 if (jsEngine_) {
564 jsEngine_->DumpHeapSnapshot(isPrivate);
565 }
566 }
567
NotifyUIIdle()568 void DeclarativeFrontendNG::NotifyUIIdle()
569 {
570 if (jsEngine_) {
571 jsEngine_->NotifyUIIdle();
572 }
573 }
574
RestoreRouterStack(const std::string & contentInfo,ContentInfoType type)575 std::pair<RouterRecoverRecord, UIContentErrorCode> DeclarativeFrontendNG::RestoreRouterStack(
576 const std::string& contentInfo, ContentInfoType type)
577 {
578 if (delegate_) {
579 return delegate_->RestoreRouterStack(contentInfo, type);
580 }
581 return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::NULL_POINTER);
582 }
583
GetContentInfo(ContentInfoType type) const584 std::string DeclarativeFrontendNG::GetContentInfo(ContentInfoType type) const
585 {
586 if (delegate_) {
587 return delegate_->GetContentInfo(type);
588 }
589 return "";
590 }
591
SetColorMode(ColorMode colorMode)592 void DeclarativeFrontendNG::SetColorMode(ColorMode colorMode)
593 {
594 // TODO: update media query infos
595 if (delegate_) {
596 delegate_->SetColorMode(colorMode);
597 }
598 }
599
RebuildAllPages()600 void DeclarativeFrontendNG::RebuildAllPages()
601 {
602 if (delegate_) {
603 delegate_->RebuildAllPages();
604 }
605 }
606
FlushReload()607 void DeclarativeFrontendNG::FlushReload()
608 {
609 if (jsEngine_) {
610 jsEngine_->FlushReload();
611 }
612 }
613
HotReload()614 void DeclarativeFrontendNG::HotReload()
615 {
616 auto manager = GetPageRouterManager();
617 CHECK_NULL_VOID(manager);
618 manager->FlushFrontend();
619 }
620
GetCurrentPageUrl() const621 std::string DeclarativeFrontendNG::GetCurrentPageUrl() const
622 {
623 auto pageRouterManager = GetPageRouterManager();
624 if (pageRouterManager) {
625 return pageRouterManager->GetCurrentPageUrl();
626 }
627 return "";
628 }
629 } // namespace OHOS::Ace
630