1 /*
2 * Copyright (c) 2022-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 "frameworks/bridge/declarative_frontend/ng/page_router_manager.h"
17
18 #include "base/i18n/localization.h"
19 #include "base/thread/task_dependency_manager.h"
20 #include "base/ressched/ressched_report.h"
21 #include "base/perfmonitor/perf_monitor.h"
22 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
23 #include "core/common/recorder/node_data_cache.h"
24 #include "core/common/thread_checker.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/base/view_advanced_register.h"
27 #include "core/components_ng/pattern/stage/page_pattern.h"
28 #include "core/components_ng/pattern/stage/stage_manager.h"
29 #include "core/components_v2/inspector/inspector_constants.h"
30 #include "core/pipeline/base/element_register.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
33
34 namespace OHOS::Ace::NG {
35
36 namespace {
37
38 constexpr int32_t BUNDLE_START_POS = 8;
39 constexpr int32_t INVALID_PAGE_INDEX = -1;
40 constexpr int32_t MAX_ROUTER_STACK_SIZE = 32;
41 constexpr int32_t JS_FILE_EXTENSION_LENGTH = 3;
42 constexpr char ETS_PATH[] = "/src/main/ets/";
43 constexpr char DEBUG_PATH[] = "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/";
44 constexpr char NEW_PATH[] = "entry|entry|1.0.0|src/main/ets/";
45 constexpr char TS_SUFFIX[] = ".ts";
46 constexpr char ETS_SUFFIX[] = ".ets";
47
ExitToDesktop()48 void ExitToDesktop()
49 {
50 auto container = Container::Current();
51 CHECK_NULL_VOID(container);
52 auto taskExecutor = container->GetTaskExecutor();
53 CHECK_NULL_VOID(taskExecutor);
54 taskExecutor->PostTask(
55 [] {
56 auto pipeline = PipelineContext::GetCurrentContext();
57 CHECK_NULL_VOID(pipeline);
58 AccessibilityEvent event;
59 event.type = AccessibilityEventType::PAGE_CHANGE;
60 pipeline->SendEventToAccessibility(event);
61 pipeline->Finish(false);
62 },
63 TaskExecutor::TaskType::UI, "ArkUIPageRouterExitToDesktop",
64 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
65 }
66
67 } // namespace
68
LoadOhmUrl(const RouterPageInfo & target)69 void PageRouterManager::LoadOhmUrl(const RouterPageInfo& target)
70 {
71 RouterPageInfo info = target;
72 info.path = info.url + ".js";
73 RouterOptScope scope(this);
74 LoadPage(GenerateNextPageId(), info);
75 }
76
RunPage(const std::string & url,const std::string & params)77 void PageRouterManager::RunPage(const std::string& url, const std::string& params)
78 {
79 PerfMonitor::GetPerfMonitor()->SetAppStartStatus();
80 ACE_SCOPED_TRACE("PageRouterManager::RunPage");
81 CHECK_RUN_ON(JS);
82 RouterPageInfo info;
83 info.url = url;
84 info.params = params;
85 #if !defined(PREVIEW)
86 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
87 info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
88 TAG_LOGE(AceLogTag::ACE_ROUTER,
89 "Router load ohmUrl failed, probably caused by invalid ohmUrl. code:%{public}d, msg:%{public}s",
90 errorCode, errorMsg.c_str());
91 };
92 auto loadTask = [weak = AceType::WeakClaim(this), info]() {
93 auto pageRouterManager = weak.Upgrade();
94 CHECK_NULL_VOID(pageRouterManager);
95 pageRouterManager->LoadOhmUrl(info);
96 };
97 auto errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
98 TAG_LOGW(AceLogTag::ACE_ROUTER, "RunPage error code:%{public}d, msg:%{public}s",
99 errorCode, errorMsg.c_str());
100 };
101 LoadOhmUrlPage(info.url, std::move(loadTask), errorCallback,
102 "ArkUIPageRouterLoadOhmUrl", "ArkUIPageRouterErrorLog");
103 return;
104 }
105 #endif
106 if (!info.url.empty()) {
107 info.path = manifestParser_->GetRouter()->GetPagePath(url);
108 if (info.path.empty()) {
109 return;
110 }
111 } else {
112 info.path = manifestParser_->GetRouter()->GetEntry();
113 info.url = manifestParser_->GetRouter()->GetEntry("");
114 }
115 RouterOptScope scope(this);
116 LoadPage(GenerateNextPageId(), info);
117 }
118
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)119 void PageRouterManager::RunPage(const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
120 {
121 CHECK_RUN_ON(JS);
122 RouterPageInfo info;
123 info.content = content;
124 info.params = params;
125
126 #if !defined(PREVIEW)
127 auto container = Container::Current();
128 CHECK_NULL_VOID(container);
129 auto instanceId = container->GetInstanceId();
130 auto taskExecutor = container->GetTaskExecutor();
131 CHECK_NULL_VOID(taskExecutor);
132 ContainerScope scope(instanceId);
133 auto pageRouterManager = AceType::Claim(this);
134 CHECK_NULL_VOID(pageRouterManager);
135 taskExecutor->PostTask(
136 [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
137 TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrlContent",
138 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
139 #endif
140 }
141
RunPageByNamedRouter(const std::string & name,const std::string & params)142 void PageRouterManager::RunPageByNamedRouter(const std::string& name, const std::string& params)
143 {
144 auto callback = [weak = AceType::WeakClaim(this), name, params]() {
145 auto pageRouterManager = weak.Upgrade();
146 CHECK_NULL_VOID(pageRouterManager);
147 pageRouterManager->RunPageByNamedRouterInner(name, params);
148 };
149 /**
150 * Always check if the namedRoute page needs to be preloaded.
151 * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
152 */
153 if (TryPreloadNamedRouter(name, std::move(callback))) {
154 return;
155 }
156
157 RunPageByNamedRouterInner(name, params);
158 }
159
RunPageByNamedRouterInner(const std::string & name,const std::string & params)160 void PageRouterManager::RunPageByNamedRouterInner(const std::string& name, const std::string& params)
161 {
162 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
163 TAG_LOGW(AceLogTag::ACE_ROUTER, "RunPageByNamedRouter exceeds maxStackSize.");
164 return;
165 }
166
167 RouterPageInfo info;
168 info.url = name;
169 info.params = params;
170 info.isNamedRouterMode = true;
171 RouterOptScope scope(this);
172 LoadPage(GenerateNextPageId(), info);
173 }
174
RunCard(const std::string & url,const std::string & params,int64_t cardId,const std::string & entryPoint)175 UIContentErrorCode PageRouterManager::RunCard(
176 const std::string& url, const std::string& params, int64_t cardId, const std::string& entryPoint)
177 {
178 CHECK_RUN_ON(JS);
179 RouterPageInfo info;
180 info.url = url;
181 #ifndef PREVIEW
182 if (!info.url.empty()) {
183 info.path = manifestParser_->GetRouter()->GetPagePath(url);
184 } else {
185 info.path = manifestParser_->GetRouter()->GetEntry();
186 info.url = manifestParser_->GetRouter()->GetEntry("");
187 }
188 #endif
189 return LoadCard(0, info, params, cardId, false, true, entryPoint);
190 }
191
Push(const RouterPageInfo & target)192 void PageRouterManager::Push(const RouterPageInfo& target)
193 {
194 CHECK_RUN_ON(JS);
195 if (inRouterOpt_) {
196 auto context = PipelineContext::GetCurrentContext();
197 CHECK_NULL_VOID(context);
198 context->PostAsyncEvent(
199 [weak = WeakClaim(this), target]() {
200 auto router = weak.Upgrade();
201 CHECK_NULL_VOID(router);
202 router->Push(target);
203 },
204 "ArkUIPageRouterPush", TaskExecutor::TaskType::JS);
205 return;
206 }
207 RouterOptScope scope(this);
208 StartPush(target);
209 }
210
TryPreloadNamedRouter(const std::string & name,std::function<void ()> && finishCallback)211 bool PageRouterManager::TryPreloadNamedRouter(const std::string& name, std::function<void()>&& finishCallback)
212 {
213 /**
214 * Before loading the namedRoute page, we need to check if it is necessary to preload the namedRoute
215 * page code (equivalent to dynamic import in ets, eg: import('hsp'); ).
216 * After preloading, pageGenerator will be filled, @sa JsiDeclarativeEngine::namedRouterRegisterMap_
217 */
218 if (!isNamedRouterNeedPreload_ || !isNamedRouterNeedPreload_(name)) {
219 return false;
220 }
221
222 if (!preloadNamedRouter_) {
223 TAG_LOGW(AceLogTag::ACE_ROUTER, "PreloadNamedRouter was not set!");
224 return false;
225 }
226
227 auto container = Container::Current();
228 CHECK_NULL_RETURN(container, false);
229 auto instanceId = container->GetInstanceId();
230 auto taskExecutor = container->GetTaskExecutor();
231 CHECK_NULL_RETURN(taskExecutor, false);
232 auto preloadFinishCallback = [taskExecutor, instanceId, callback = std::move(finishCallback), name](bool success) {
233 if (!success) {
234 TAG_LOGW(AceLogTag::ACE_ROUTER, "failed to preload NamedRouter: %{public}s", name.c_str());
235 return;
236 }
237 taskExecutor->PostTask(
238 [instanceId, finishCallback = std::move(callback)]() {
239 ContainerScope scope(instanceId);
240 if (finishCallback) {
241 finishCallback();
242 }
243 }, TaskExecutor::TaskType::JS, "ArkUIPageRouterPreloadNamedRouterFinishCallback",
244 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
245 };
246 preloadNamedRouter_(name, std::move(preloadFinishCallback));
247 return true;
248 }
249
PushNamedRoute(const RouterPageInfo & target)250 void PageRouterManager::PushNamedRoute(const RouterPageInfo& target)
251 {
252 auto callback = [weak = AceType::WeakClaim(this), target]() {
253 auto pageRouterManager = weak.Upgrade();
254 CHECK_NULL_VOID(pageRouterManager);
255 pageRouterManager->PushNamedRouteInner(target);
256 };
257 /**
258 * Always check if the namedRoute page needs to be preloaded.
259 * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
260 */
261 if (TryPreloadNamedRouter(target.url, std::move(callback))) {
262 return;
263 }
264
265 PushNamedRouteInner(target);
266 }
267
PushNamedRouteInner(const RouterPageInfo & target)268 void PageRouterManager::PushNamedRouteInner(const RouterPageInfo& target)
269 {
270 CHECK_RUN_ON(JS);
271 if (inRouterOpt_) {
272 auto context = PipelineContext::GetCurrentContext();
273 CHECK_NULL_VOID(context);
274 context->PostAsyncEvent(
275 [weak = WeakClaim(this), target]() {
276 auto router = weak.Upgrade();
277 CHECK_NULL_VOID(router);
278 router->PushNamedRouteInner(target);
279 },
280 "ArkUIPageRouterPushNamedRoute", TaskExecutor::TaskType::JS);
281 return;
282 }
283 RouterOptScope scope(this);
284 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
285 TAG_LOGW(AceLogTag::ACE_ROUTER, "PushNamedRoute exceeds maxStackSize.");
286 if (target.errorCallback != nullptr) {
287 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
288 }
289 return;
290 }
291 CleanPageOverlay();
292 UpdateSrcPage();
293 if (target.routerMode == RouterMode::SINGLE) {
294 auto pageInfoByUrl = FindPageInStackByRouteName(target.url);
295 if (pageInfoByUrl.second) {
296 // find page in stack, move postion and update params.
297 auto pagePattern = pageInfoByUrl.second->GetPattern<PagePattern>();
298 if (pagePattern) {
299 pagePattern->FireOnNewParam(target.params);
300 }
301 MovePageToFront(pageInfoByUrl.first, pageInfoByUrl.second, target, true);
302 return;
303 }
304 auto index = FindPageInRestoreStack(target.url);
305 if (index != INVALID_PAGE_INDEX) {
306 // find page in restore page, create page, move position and update params.
307 RestorePageWithTarget(index, false, target, RestorePageDestination::TOP);
308 return;
309 }
310 }
311 RouterPageInfo info = target;
312 info.isNamedRouterMode = true;
313 LoadPage(GenerateNextPageId(), info, true, true, true);
314 }
315
Replace(const RouterPageInfo & target)316 void PageRouterManager::Replace(const RouterPageInfo& target)
317 {
318 CHECK_RUN_ON(JS);
319 if (inRouterOpt_) {
320 auto context = PipelineContext::GetCurrentContext();
321 CHECK_NULL_VOID(context);
322 context->PostAsyncEvent(
323 [weak = WeakClaim(this), target]() {
324 auto router = weak.Upgrade();
325 CHECK_NULL_VOID(router);
326 router->Replace(target);
327 },
328 "ArkUIPageRouterReplace", TaskExecutor::TaskType::JS);
329 return;
330 }
331 RouterOptScope scope(this);
332 StartReplace(target);
333 }
334
ReplaceNamedRoute(const RouterPageInfo & target)335 void PageRouterManager::ReplaceNamedRoute(const RouterPageInfo& target)
336 {
337 auto callback = [weak = AceType::WeakClaim(this), target]() {
338 auto pageRouterManager = weak.Upgrade();
339 CHECK_NULL_VOID(pageRouterManager);
340 pageRouterManager->ReplaceNamedRouteInner(target);
341 };
342 /**
343 * Always check if the namedRoute page needs to be preloaded.
344 * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
345 */
346 if (TryPreloadNamedRouter(target.url, std::move(callback))) {
347 return;
348 }
349
350 ReplaceNamedRouteInner(target);
351 }
352
ReplaceNamedRouteInner(const RouterPageInfo & target)353 void PageRouterManager::ReplaceNamedRouteInner(const RouterPageInfo& target)
354 {
355 CHECK_RUN_ON(JS);
356 if (inRouterOpt_) {
357 auto context = PipelineContext::GetCurrentContext();
358 CHECK_NULL_VOID(context);
359 context->PostAsyncEvent(
360 [weak = WeakClaim(this), target]() {
361 auto router = weak.Upgrade();
362 CHECK_NULL_VOID(router);
363 router->ReplaceNamedRouteInner(target);
364 },
365 "ArkUIPageRouterReplaceNamedRoute", TaskExecutor::TaskType::JS);
366 return;
367 }
368 RouterOptScope scope(this);
369 CleanPageOverlay();
370 UpdateSrcPage();
371 RouterPageInfo info = target;
372 info.isNamedRouterMode = true;
373 DealReplacePage(info);
374 }
375
BackWithTarget(const RouterPageInfo & target)376 void PageRouterManager::BackWithTarget(const RouterPageInfo& target)
377 {
378 CHECK_RUN_ON(JS);
379 TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back path:%{public}s", target.url.c_str());
380 if (inRouterOpt_) {
381 auto context = PipelineContext::GetCurrentContext();
382 CHECK_NULL_VOID(context);
383 context->PostAsyncEvent(
384 [weak = WeakClaim(this), target]() {
385 auto router = weak.Upgrade();
386 CHECK_NULL_VOID(router);
387 router->BackWithTarget(target);
388 },
389 "ArkUIPageRouterBackWithTarget", TaskExecutor::TaskType::JS);
390 return;
391 }
392 RouterOptScope scope(this);
393 BackCheckAlert(target);
394 }
395
BackToIndexWithTarget(int32_t index,const std::string & params)396 void PageRouterManager::BackToIndexWithTarget(int32_t index, const std::string& params)
397 {
398 CHECK_RUN_ON(JS);
399 if (!CheckIndexValid(index)) {
400 return;
401 }
402 if (inRouterOpt_) {
403 auto context = PipelineContext::GetCurrentContext();
404 CHECK_NULL_VOID(context);
405 context->PostAsyncEvent(
406 [weak = WeakClaim(this), index, params]() {
407 auto router = weak.Upgrade();
408 CHECK_NULL_VOID(router);
409 router->BackToIndexWithTarget(index, params);
410 },
411 "ArkUIPageRouterBackToIndex", TaskExecutor::TaskType::JS);
412 return;
413 }
414 RouterOptScope scope(this);
415 BackToIndexCheckAlert(index, params);
416 }
417
Clear()418 void PageRouterManager::Clear()
419 {
420 CHECK_RUN_ON(JS);
421 if (inRouterOpt_) {
422 auto context = PipelineContext::GetCurrentContext();
423 CHECK_NULL_VOID(context);
424 context->PostAsyncEvent(
425 [weak = WeakClaim(this)]() {
426 auto router = weak.Upgrade();
427 CHECK_NULL_VOID(router);
428 router->Clear();
429 },
430 "ArkUIPageRouterClear", TaskExecutor::TaskType::JS);
431 return;
432 }
433 RouterOptScope scope(this);
434 StartClean();
435 }
436
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)437 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
438 {
439 auto currentPage = GetCurrentPageNode();
440 CHECK_NULL_VOID(currentPage);
441 auto pagePattern = currentPage->GetPattern<PagePattern>();
442 CHECK_NULL_VOID(pagePattern);
443 auto pageInfo = pagePattern->GetPageInfo();
444 CHECK_NULL_VOID(pageInfo);
445
446 DialogProperties dialogProperties = {
447 .content = message,
448 .autoCancel = false,
449 .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
450 { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
451 .onSuccess =
452 [weak = AceType::WeakClaim(this), weakPageInfo = AceType::WeakClaim(AceType::RawPtr(pageInfo))](
453 int32_t successType, int32_t successIndex) {
454 auto pageInfo = weakPageInfo.Upgrade();
455 if (pageInfo && pageInfo->GetAlertCallback() && !successType) {
456 pageInfo->GetAlertCallback()(successIndex);
457 if (successIndex) {
458 auto router = weak.Upgrade();
459 CHECK_NULL_VOID(router);
460 router->StartBack(router->ngBackTarget_);
461 }
462 }
463 },
464 };
465
466 pageInfo->SetDialogProperties(dialogProperties);
467 pageInfo->SetAlertCallback(std::move(callback));
468 }
469
DisableAlertBeforeBackPage()470 void PageRouterManager::DisableAlertBeforeBackPage()
471 {
472 if (pageRouterStack_.empty()) {
473 return;
474 }
475 auto currentPage = GetCurrentPageNode();
476 CHECK_NULL_VOID(currentPage);
477 auto pagePattern = currentPage->GetPattern<PagePattern>();
478 CHECK_NULL_VOID(pagePattern);
479 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
480 CHECK_NULL_VOID(pageInfo);
481 pageInfo->SetAlertCallback(nullptr);
482 }
483
StartClean()484 void PageRouterManager::StartClean()
485 {
486 UpdateSrcPage();
487 if (pageRouterStack_.size() > 1) {
488 restorePageStack_.clear();
489 std::list<WeakPtr<FrameNode>> temp;
490 std::swap(temp, pageRouterStack_);
491 pageRouterStack_.emplace_back(temp.back());
492 if (!OnCleanPageStack()) {
493 std::swap(temp, pageRouterStack_);
494 } else {
495 RefreshPageIndex(pageRouterStack_.begin(), 0);
496 }
497 return;
498 }
499
500 if (pageRouterStack_.size() == 1) {
501 restorePageStack_.clear();
502 return;
503 }
504 }
505
Pop()506 bool PageRouterManager::Pop()
507 {
508 CHECK_RUN_ON(JS);
509 if (inRouterOpt_) {
510 TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop is in routeropt");
511 return false;
512 }
513 RouterOptScope scope(this);
514 return StartPop();
515 }
516
StartPop()517 bool PageRouterManager::StartPop()
518 {
519 CHECK_RUN_ON(JS);
520 auto currentPage = GetCurrentPageNode();
521 CHECK_NULL_RETURN(currentPage, false);
522 auto pagePattern = currentPage->GetPattern<PagePattern>();
523 CHECK_NULL_RETURN(pagePattern, false);
524 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
525 CHECK_NULL_RETURN(pageInfo, false);
526 if (pageInfo->GetAlertCallback()) {
527 TAG_LOGI(AceLogTag::ACE_ROUTER, "pop alert check start");
528 BackCheckAlert(RouterPageInfo());
529 return true;
530 }
531
532 if (pageRouterStack_.size() <= 1) {
533 if (!restorePageStack_.empty()) {
534 StartRestore(RouterPageInfo());
535 return true;
536 }
537 // the last page.
538 return false;
539 }
540 UpdateSrcPage();
541 // pop top page in page stack
542 auto preWeakNode = pageRouterStack_.back();
543 pageRouterStack_.pop_back();
544
545 // clean prev top page params
546 currentPage = GetCurrentPageNode();
547 CHECK_NULL_RETURN(currentPage, false);
548 pagePattern = currentPage->GetPattern<PagePattern>();
549 CHECK_NULL_RETURN(pagePattern, false);
550 pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
551 CHECK_NULL_RETURN(pageInfo, false);
552 std::string params = pageInfo->GetPageParams();
553 pageInfo->ReplacePageParams("");
554
555 // do pop page
556 if (!OnPopPage(true, true)) {
557 pageRouterStack_.emplace_back(preWeakNode);
558 pageInfo->ReplacePageParams(params);
559 return false;
560 }
561 return true;
562 }
563
StartRestore(const RouterPageInfo & target)564 void PageRouterManager::StartRestore(const RouterPageInfo& target)
565 {
566 RouterPageInfo info = target;
567 auto tempStack = restorePageStack_;
568 if (!target.url.empty()) {
569 while (!tempStack.empty() && tempStack.back().url != info.url) {
570 tempStack.pop_back();
571 }
572 if (tempStack.empty()) {
573 return;
574 }
575 }
576 info.url = tempStack.back().url;
577 info.params = target.params;
578 info.recoverable = true;
579 info.isNamedRouterMode = tempStack.back().isNamedRouter;
580 tempStack.pop_back();
581 restorePageStack_ = tempStack;
582
583 if (info.isNamedRouterMode) {
584 if (manifestParser_) {
585 if (manifestParser_->GetRouter()->GetPagePath(info.url).empty()) {
586 manifestParser_->SetPagePath(info.url);
587 }
588 }
589 }
590
591 if (info.isNamedRouterMode) {
592 auto callback = [weak = AceType::WeakClaim(this), info]() {
593 auto pageRouterManager = weak.Upgrade();
594 CHECK_NULL_VOID(pageRouterManager);
595 pageRouterManager->RestorePageWithTargetInner(info, RestorePageDestination::BELLOW_TOP);
596 };
597 /**
598 * Always check if the namedRoute page needs to be preloaded.
599 * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
600 */
601 if (TryPreloadNamedRouter(info.url, std::move(callback))) {
602 return;
603 }
604 }
605
606 RestorePageWithTargetInner(info, RestorePageDestination::BELLOW_TOP);
607 }
608
GetStackSize() const609 int32_t PageRouterManager::GetStackSize() const
610 {
611 CHECK_RUN_ON(JS);
612 auto stackSize = static_cast<int32_t>(pageRouterStack_.size() + restorePageStack_.size());
613 if (isNewPageReplacing_) {
614 stackSize--;
615 }
616 return stackSize;
617 }
618
GetCurrentPageIndex() const619 int32_t PageRouterManager::GetCurrentPageIndex() const
620 {
621 /**
622 * In various page stack operations, pages may be inserted into different positions on the page stack,
623 * and corresponding pages may also have different indexes.
624 */
625 CHECK_RUN_ON(JS);
626 if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BELLOW_TOP) {
627 // Page has been inserted into position bellow top page of pageRouterStack_.
628 return static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size()) - 1;
629 } else if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BOTTOM) {
630 // Page has been inserted into bottom position of pageRouterStack_.
631 return static_cast<int32_t>(restorePageStack_.size()) + 1;
632 } else {
633 // Page has been inserted into top position of pageRouterStack_.
634 auto index = static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size());
635 if (isNewPageReplacing_) {
636 /**
637 * example:
638 * stack bottom -> stack top
639 * [1]PageA -> [2]PageB
640 * call router.replace(PageC)
641 * then we need keep index of PageC same with PageB, that is 2
642 */
643 index--;
644 }
645 return index;
646 }
647 }
648
GetPageInfoByIndex(int32_t index,const std::string & params)649 RouterPageInfo PageRouterManager::GetPageInfoByIndex(int32_t index, const std::string& params)
650 {
651 RouterPageInfo emptyForReturn;
652 if (!CheckIndexValid(index) &&
653 index != (GetStackSize() + 1) /* in case the page is on popping */) {
654 return emptyForReturn;
655 }
656
657 if (index <= static_cast<int32_t>(restorePageStack_.size())) {
658 auto it = restorePageStack_.begin();
659 std::advance(it, index - 1);
660 RouterPageInfo info;
661 info.url = it->url;
662 info.params = params;
663 info.recoverable = true;
664 info.isNamedRouterMode = it->isNamedRouter;
665 return info;
666 }
667
668 auto createPageInfo = [¶ms](const RefPtr<NG::EntryPageInfo>& pageInfo) -> RouterPageInfo {
669 RouterPageInfo info;
670 info.url = pageInfo->GetPageUrl();
671 info.params = params;
672 info.recoverable = pageInfo->IsRecoverable();
673 info.isNamedRouterMode = pageInfo->IsCreateByNamedRouter();
674 return info;
675 };
676 if (index <= static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size())) {
677 auto it = pageRouterStack_.begin();
678 std::advance(it, index - static_cast<int32_t>(restorePageStack_.size()) - 1);
679 auto pageNode = it->Upgrade();
680 CHECK_NULL_RETURN(pageNode, emptyForReturn);
681 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
682 CHECK_NULL_RETURN(pagePattern, emptyForReturn);
683 auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
684 CHECK_NULL_RETURN(pageInfo, emptyForReturn);
685 return createPageInfo(pageInfo);
686 }
687
688 // in case the page is on popping
689 auto pipelineContext = PipelineContext::GetCurrentContext();
690 CHECK_NULL_RETURN(pipelineContext, emptyForReturn);
691 auto stageManager = pipelineContext->GetStageManager();
692 CHECK_NULL_RETURN(stageManager, emptyForReturn);
693 auto popPage = stageManager->GetLastPage();
694 CHECK_NULL_RETURN(popPage, emptyForReturn);
695 auto pagePattern = popPage->GetPattern<NG::PagePattern>();
696 CHECK_NULL_RETURN(pagePattern, emptyForReturn);
697 auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
698 // make sure the last page is the one with 'index'
699 if (pageInfo && pageInfo->GetPageIndex() == index) {
700 return createPageInfo(pageInfo);
701 }
702
703 return emptyForReturn;
704 }
705
GetState(int32_t & index,std::string & name,std::string & path)706 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
707 {
708 CHECK_RUN_ON(JS);
709 if (pageRouterStack_.empty()) {
710 return;
711 }
712 index = static_cast<int32_t>(pageRouterStack_.size() + restorePageStack_.size());
713 if (isNewPageReplacing_) {
714 if (index <= 1) {
715 TAG_LOGD(AceLogTag::ACE_ROUTER, "router stack size invalid while replacing");
716 } else {
717 index = index - 1;
718 }
719 }
720 auto pageNode = GetCurrentPageNode();
721 CHECK_NULL_VOID(pageNode);
722 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
723 CHECK_NULL_VOID(pagePattern);
724 auto pageInfo = pagePattern->GetPageInfo();
725 CHECK_NULL_VOID(pageInfo);
726 auto url = pageInfo->GetPageUrl();
727 GetPageNameAndPath(url, name, path);
728 }
729
GetStateByIndex(int32_t index,std::string & name,std::string & path,std::string & params)730 void PageRouterManager::GetStateByIndex(int32_t index, std::string& name, std::string& path, std::string& params)
731 {
732 CHECK_RUN_ON(JS);
733 if (!CheckIndexValid(index) &&
734 index != (GetStackSize() + 1) /* in case the page is on popping */) {
735 return;
736 }
737
738 if (index <= static_cast<int32_t>(restorePageStack_.size())) {
739 auto it = restorePageStack_.begin();
740 std::advance(it, index - 1);
741 GetPageNameAndPath(it->url, name, path);
742 params = it->params;
743 return;
744 }
745
746 if (index <= static_cast<int32_t>(restorePageStack_.size() + pageRouterStack_.size())) {
747 auto it = pageRouterStack_.begin();
748 std::advance(it, index - static_cast<int32_t>(restorePageStack_.size()) - 1);
749 auto pageNode = it->Upgrade();
750 CHECK_NULL_VOID(pageNode);
751 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
752 CHECK_NULL_VOID(pagePattern);
753 auto pageInfo = AceType::DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
754 CHECK_NULL_VOID(pageInfo);
755 auto url = pageInfo->GetPageUrl();
756 GetPageNameAndPath(url, name, path);
757 params = pageInfo->GetPageParams();
758 return;
759 }
760
761 // in case the page is on popping
762 auto pipelineContext = PipelineContext::GetCurrentContext();
763 CHECK_NULL_VOID(pipelineContext);
764 auto stageManager = pipelineContext->GetStageManager();
765 CHECK_NULL_VOID(stageManager);
766 auto popPage = stageManager->GetLastPage();
767 CHECK_NULL_VOID(popPage);
768 auto pagePattern = popPage->GetPattern<NG::PagePattern>();
769 CHECK_NULL_VOID(pagePattern);
770 auto pageInfo = pagePattern->GetPageInfo();
771 // make sure the last page is the one with 'index'
772 if (pageInfo && pageInfo->GetPageIndex() == index) {
773 auto url = pageInfo->GetPageUrl();
774 GetPageNameAndPath(url, name, path);
775 auto entryPageInfo = DynamicCast<NG::EntryPageInfo>(pageInfo);
776 CHECK_NULL_VOID(entryPageInfo);
777 params = entryPageInfo->GetPageParams();
778 }
779 }
780
GetStateByUrl(std::string & url,std::vector<Framework::StateInfo> & stateArray)781 void PageRouterManager::GetStateByUrl(std::string& url, std::vector<Framework::StateInfo>& stateArray)
782 {
783 CHECK_RUN_ON(JS);
784 int32_t counter = 1;
785 Framework::StateInfo stateInfo;
786 GetPageNameAndPath(url, stateInfo.name, stateInfo.path);
787
788 for (const auto& record : restorePageStack_) {
789 if (record.url == url) {
790 stateInfo.params = record.params;
791 stateInfo.index = counter;
792 stateArray.emplace_back(stateInfo);
793 }
794 counter++;
795 }
796 for (auto& iter : pageRouterStack_) {
797 auto pageNode = iter.Upgrade();
798 CHECK_NULL_VOID(pageNode);
799 auto pagePattern = pageNode->GetPattern<PagePattern>();
800 CHECK_NULL_VOID(pagePattern);
801 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
802 CHECK_NULL_VOID(pageInfo);
803 if (pageInfo->GetPageUrl() == url) {
804 stateInfo.params = pageInfo->GetPageParams();
805 stateInfo.index = counter;
806 stateArray.emplace_back(stateInfo);
807 }
808 counter++;
809 }
810 }
811
GetPageNameAndPath(const std::string & url,std::string & name,std::string & path)812 void PageRouterManager::GetPageNameAndPath(const std::string& url, std::string& name, std::string& path)
813 {
814 std::string tempUrl = url;
815 auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
816 if (!pagePath.empty()) {
817 tempUrl = pagePath;
818 }
819 auto pos = tempUrl.rfind(".js");
820 if (pos == tempUrl.length() - JS_FILE_EXTENSION_LENGTH) {
821 tempUrl = tempUrl.substr(0, pos);
822 }
823 pos = tempUrl.rfind("/");
824 if (pos != std::string::npos) {
825 name = tempUrl.substr(pos + 1);
826 path = tempUrl.substr(0, pos + 1);
827 }
828 if (name.size() == 0) {
829 name = "index";
830 }
831 if (path.size() == 0) {
832 path = "/" + tempUrl;
833 }
834 }
835
GetParams() const836 std::string PageRouterManager::GetParams() const
837 {
838 CHECK_RUN_ON(JS);
839 RefPtr<FrameNode> pageNode = nullptr;
840 if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BELLOW_TOP) {
841 constexpr size_t STACK_SIZE = 2;
842 if (pageRouterStack_.size() < STACK_SIZE) {
843 return "";
844 }
845 auto it = pageRouterStack_.rbegin();
846 ++it;
847 pageNode = it->Upgrade();
848 } else if (insertPageProcessingType_ == InsertPageProcessingType::INSERT_BOTTOM) {
849 if (pageRouterStack_.empty()) {
850 return "";
851 }
852 pageNode = pageRouterStack_.front().Upgrade();
853 } else {
854 if (pageRouterStack_.empty()) {
855 return "";
856 }
857 pageNode = GetCurrentPageNode();
858 }
859
860 CHECK_NULL_RETURN(pageNode, "");
861 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
862 CHECK_NULL_RETURN(pagePattern, "");
863 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
864 CHECK_NULL_RETURN(pageInfo, "");
865 return pageInfo->GetPageParams();
866 }
867
GetIndexByUrl(const std::string & url) const868 int32_t PageRouterManager::GetIndexByUrl(const std::string& url) const
869 {
870 int32_t index = 0;
871 for (auto iter : pageRouterStack_) {
872 auto pageNode = iter.Upgrade();
873 if (!pageNode) {
874 continue;
875 }
876 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
877 auto localUrl = pagePattern->GetPageInfo()->GetPageUrl();
878 if (localUrl == url) {
879 return index;
880 }
881 ++index;
882 }
883 return INVALID_PAGE_INDEX;
884 }
885
GetCurrentPageUrl()886 std::string PageRouterManager::GetCurrentPageUrl()
887 {
888 CHECK_RUN_ON(JS);
889 if (pageRouterStack_.empty()) {
890 return "";
891 }
892 auto pageNode = GetCurrentPageNode();
893 CHECK_NULL_RETURN(pageNode, "");
894 auto pagePattern = pageNode->GetPattern<PagePattern>();
895 CHECK_NULL_RETURN(pagePattern, "");
896 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
897 CHECK_NULL_RETURN(entryPageInfo, "");
898 return entryPageInfo->GetPagePath();
899 }
900
901 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)902 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
903 {
904 CHECK_RUN_ON(JS);
905 if (pageRouterStack_.empty()) {
906 return nullptr;
907 }
908 auto pageNode = GetCurrentPageNode();
909 CHECK_NULL_RETURN(pageNode, nullptr);
910 auto pagePattern = pageNode->GetPattern<PagePattern>();
911 CHECK_NULL_RETURN(pagePattern, nullptr);
912 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
913 CHECK_NULL_RETURN(entryPageInfo, nullptr);
914 auto pageMap = entryPageInfo->GetPageMap();
915 if (pageMap) {
916 return pageMap;
917 }
918 // initialize page map.
919 std::string jsSourceMap;
920 // stage mode
921 auto container = Container::Current();
922 CHECK_NULL_RETURN(container, nullptr);
923 if (container->IsUseStageModel()) {
924 auto pagePath = entryPageInfo->GetPagePath();
925 auto moduleName = container->GetModuleName();
926 std::string judgePath = "";
927 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
928 judgePath = DEBUG_PATH + moduleName + ETS_PATH +
929 pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
930 } else {
931 judgePath = moduleName + ETS_PATH +
932 pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + ETS_SUFFIX;
933 }
934 if (Framework::GetAssetContentImpl(assetManager, "sourceMaps.map", jsSourceMap)) {
935 auto jsonPages = JsonUtil::ParseJsonString(jsSourceMap);
936 auto child = jsonPages->GetChild();
937 if (!child->GetValue("entry-package-info")->IsNull()) {
938 judgePath = NEW_PATH + pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
939 }
940 auto jsonPage = jsonPages->GetValue(judgePath)->ToString();
941 auto stagePageMap = MakeRefPtr<Framework::RevSourceMap>();
942 stagePageMap->Init(jsonPage);
943 entryPageInfo->SetPageMap(stagePageMap);
944 return stagePageMap;
945 }
946 } else {
947 if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
948 auto faPageMap = MakeRefPtr<Framework::RevSourceMap>();
949 faPageMap->Init(jsSourceMap);
950 entryPageInfo->SetPageMap(faPageMap);
951 return faPageMap;
952 }
953 }
954 return nullptr;
955 }
956
GetStackInfo(ContentInfoType type)957 std::unique_ptr<JsonValue> PageRouterManager::GetStackInfo(ContentInfoType type)
958 {
959 auto jsonRouterStack = JsonUtil::CreateArray(true);
960 auto restoreIter = restorePageStack_.begin();
961 while (restoreIter != restorePageStack_.end()) {
962 auto jsonItem = JsonUtil::Create(true);
963 jsonItem->Put("url", restoreIter->url.c_str());
964 if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
965 jsonItem->Put("params", restoreIter->params.c_str());
966 jsonItem->Put("isNamedRoute", restoreIter->isNamedRouter);
967 }
968 jsonRouterStack->Put(jsonItem);
969 ++restoreIter;
970 }
971 auto iter = pageRouterStack_.begin();
972 while (iter != pageRouterStack_.end()) {
973 auto pageNode = iter->Upgrade();
974 CHECK_NULL_RETURN(pageNode, jsonRouterStack);
975 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
976 CHECK_NULL_RETURN(pagePattern, jsonRouterStack);
977 auto pageInfo = AceType::DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
978 CHECK_NULL_RETURN(pageInfo, jsonRouterStack);
979 if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY && !pageInfo->IsRecoverable()) {
980 ++iter;
981 continue;
982 }
983 auto url = pageInfo->GetPageUrl();
984 auto jsonItem = JsonUtil::Create(true);
985 jsonItem->Put("url", url.c_str());
986 if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
987 jsonItem->Put("params", pageInfo->GetPageParams().c_str());
988 jsonItem->Put("isNamedRoute", pageInfo->IsCreateByNamedRouter());
989 }
990 jsonRouterStack->Put(jsonItem);
991 ++iter;
992 }
993 return jsonRouterStack;
994 }
995
GetNamedRouterInfo()996 std::unique_ptr<JsonValue> PageRouterManager::GetNamedRouterInfo()
997 {
998 if (getNamedRouterInfo_) {
999 return getNamedRouterInfo_();
1000 }
1001 return nullptr;
1002 }
1003
RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo,ContentInfoType type)1004 std::pair<RouterRecoverRecord, UIContentErrorCode> PageRouterManager::RestoreRouterStack(
1005 std::unique_ptr<JsonValue> stackInfo, ContentInfoType type)
1006 {
1007 if (!stackInfo->IsValid() || !stackInfo->IsArray()) {
1008 return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
1009 }
1010 int32_t stackSize = stackInfo->GetArraySize();
1011 if (stackSize < 1) {
1012 return std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER);
1013 }
1014
1015 auto container = Container::Current();
1016 CHECK_NULL_RETURN(container,
1017 std::make_pair(RouterRecoverRecord(), UIContentErrorCode::NULL_POINTER));
1018 auto pipeline = container->GetPipelineContext();
1019 CHECK_NULL_RETURN(pipeline,
1020 std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER));
1021 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1022 auto stageManager = context ? context->GetStageManager() : nullptr;
1023 CHECK_NULL_RETURN(stageManager,
1024 std::make_pair(RouterRecoverRecord(), UIContentErrorCode::WRONG_PAGE_ROUTER));
1025
1026 RouterRecoverRecord topRecord;
1027 for (int32_t index = 0; index < stackSize; ++index) {
1028 auto item = stackInfo->GetArrayItem(index);
1029 bool isNamedRoute = false;
1030 std::string params;
1031 if (type == ContentInfoType::RESOURCESCHEDULE_RECOVERY) {
1032 auto isNamedRouteJson = item->GetValue("isNamedRoute");
1033 if (isNamedRouteJson && isNamedRouteJson->IsBool()) {
1034 isNamedRoute = isNamedRouteJson->GetBool();
1035 }
1036 auto paramsJson = item->GetValue("params");
1037 if (paramsJson && paramsJson->IsString()) {
1038 params = paramsJson->GetString();
1039 }
1040 }
1041
1042 std::string url = item->GetValue("url")->ToString();
1043 // remove 2 useless character, as "XXX" to XXX
1044 url = url.substr(1, url.size() - 2);
1045 if (index < stackSize - 1) {
1046 restorePageStack_.emplace_back(url, params, isNamedRoute);
1047 } else {
1048 topRecord = RouterRecoverRecord(url, params, isNamedRoute);
1049 }
1050 }
1051 return std::make_pair(topRecord, UIContentErrorCode::NO_ERRORS);
1052 }
1053
RestoreNamedRouterInfo(std::unique_ptr<JsonValue> namedRouterInfo)1054 void PageRouterManager::RestoreNamedRouterInfo(std::unique_ptr<JsonValue> namedRouterInfo)
1055 {
1056 if (restoreNamedRouterInfo_) {
1057 restoreNamedRouterInfo_(std::move(namedRouterInfo));
1058 }
1059 }
1060
GetFullPathInfo()1061 std::unique_ptr<JsonValue> PageRouterManager::GetFullPathInfo()
1062 {
1063 if (getFullPathInfo_) {
1064 return getFullPathInfo_();
1065 }
1066 return nullptr;
1067 }
1068
RestoreFullPathInfo(std::unique_ptr<JsonValue> fullPathInfo)1069 void PageRouterManager::RestoreFullPathInfo(std::unique_ptr<JsonValue> fullPathInfo)
1070 {
1071 if (restoreFullPathInfo_) {
1072 restoreFullPathInfo_(std::move(fullPathInfo));
1073 }
1074 }
1075
IsUnrestoreByIndex(int32_t index)1076 bool PageRouterManager::IsUnrestoreByIndex(int32_t index)
1077 {
1078 return index > 0 && index <= static_cast<int32_t>(restorePageStack_.size());
1079 }
1080
GenerateNextPageId()1081 int32_t PageRouterManager::GenerateNextPageId()
1082 {
1083 return ++pageId_;
1084 }
1085
FindPageInStack(const std::string & url,bool needIgnoreBegin)1086 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url, bool needIgnoreBegin)
1087 {
1088 auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
1089 pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
1090 auto pageNode = item.Upgrade();
1091 CHECK_NULL_RETURN(pageNode, false);
1092 auto pagePattern = pageNode->GetPattern<PagePattern>();
1093 CHECK_NULL_RETURN(pagePattern, false);
1094 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1095 CHECK_NULL_RETURN(entryPageInfo, false);
1096 return entryPageInfo->GetPageUrl() == url;
1097 });
1098 if (iter == pageRouterStack_.rend()) {
1099 return { INVALID_PAGE_INDEX, nullptr };
1100 }
1101 // Returns to the forward position.
1102 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
1103 }
1104
FindPageInStackByRouteName(const std::string & name,bool needIgnoreBegin)1105 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStackByRouteName(
1106 const std::string& name, bool needIgnoreBegin)
1107 {
1108 auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
1109 pageRouterStack_.rend(), [name](const WeakPtr<FrameNode>& item) {
1110 auto pageNode = item.Upgrade();
1111 CHECK_NULL_RETURN(pageNode, false);
1112 auto pagePattern = pageNode->GetPattern<PagePattern>();
1113 CHECK_NULL_RETURN(pagePattern, false);
1114 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1115 CHECK_NULL_RETURN(entryPageInfo, false);
1116 return entryPageInfo->GetRouteName() == name;
1117 });
1118 if (iter == pageRouterStack_.rend()) {
1119 return { INVALID_PAGE_INDEX, nullptr };
1120 }
1121 // Returns to the forward position.
1122 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
1123 }
1124
FindPageInRestoreStack(const std::string & url)1125 int32_t PageRouterManager::FindPageInRestoreStack(const std::string& url)
1126 {
1127 auto iter = std::find_if(restorePageStack_.rbegin(), restorePageStack_.rend(),
1128 [&url](const RouterRecoverRecord& record) {
1129 return record.url == url;
1130 });
1131 if (iter == restorePageStack_.rend()) {
1132 return INVALID_PAGE_INDEX;
1133 }
1134
1135 return std::distance(iter, restorePageStack_.rend()) - 1;
1136 }
1137
PushOhmUrl(const RouterPageInfo & target)1138 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target)
1139 {
1140 RouterOptScope scope(this);
1141 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
1142 TAG_LOGW(AceLogTag::ACE_ROUTER, "PushOhmUrl exceeds maxStackSize.");
1143 if (target.errorCallback != nullptr) {
1144 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
1145 }
1146 return;
1147 }
1148 RouterPageInfo info = target;
1149 info.path = info.url + ".js";
1150
1151 if (target.routerMode == RouterMode::SINGLE) {
1152 auto pageInfo = FindPageInStack(info.url);
1153 if (pageInfo.second) {
1154 // find page in stack, move postion and update params.
1155 auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1156 if (pagePattern) {
1157 pagePattern->FireOnNewParam(info.params);
1158 }
1159 MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1160 return;
1161 }
1162 auto index = FindPageInRestoreStack(info.url);
1163 if (index != INVALID_PAGE_INDEX) {
1164 // find page in restore page, create page, move position and update params.
1165 RestorePageWithTarget(index, false, info, RestorePageDestination::TOP);
1166 return;
1167 }
1168 }
1169
1170 LoadPage(GenerateNextPageId(), info, true, true, true);
1171 auto container = Container::Current();
1172 CHECK_NULL_VOID(container);
1173 auto pageUrlChecker = container->GetPageUrlChecker();
1174 CHECK_NULL_VOID(pageUrlChecker);
1175 auto taskExecutor = container->GetTaskExecutor();
1176 CHECK_NULL_VOID(taskExecutor);
1177 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1178 TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterPushOhmUrl",
1179 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::HIGH));
1180 }
1181
StartPush(const RouterPageInfo & target)1182 void PageRouterManager::StartPush(const RouterPageInfo& target)
1183 {
1184 CHECK_RUN_ON(JS);
1185 RouterOptScope scope(this);
1186 if (target.url.empty()) {
1187 TAG_LOGE(AceLogTag::ACE_ROUTER, "push url is empty");
1188 return;
1189 }
1190 #if !defined(PREVIEW)
1191 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1192 auto loadTask = [weak = AceType::WeakClaim(this), target]() {
1193 auto pageRouterManager = weak.Upgrade();
1194 CHECK_NULL_VOID(pageRouterManager);
1195 pageRouterManager->UpdateSrcPage();
1196 pageRouterManager->PushOhmUrl(target);
1197 };
1198 LoadOhmUrlPage(target.url, std::move(loadTask), target.errorCallback,
1199 "ArkUIPageRouterPushOhmUrl", "ArkUIPageRouterPushErrorCallback");
1200 return;
1201 }
1202 #endif
1203 if (!manifestParser_) {
1204 return;
1205 }
1206 auto context = PipelineContext::GetCurrentContext();
1207 CHECK_NULL_VOID(context);
1208 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE && !context->GetForceSplitEnable()) {
1209 TAG_LOGW(AceLogTag::ACE_ROUTER, "StartPush exceeds maxStackSize.");
1210 if (target.errorCallback != nullptr) {
1211 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
1212 }
1213 return;
1214 }
1215 RouterPageInfo info = target;
1216 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1217 if (info.path.empty()) {
1218 TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartPush with url: %{public}s", info.url.c_str());
1219 if (info.errorCallback != nullptr) {
1220 info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
1221 }
1222 return;
1223 }
1224
1225 CleanPageOverlay();
1226 UpdateSrcPage();
1227
1228 if (info.routerMode == RouterMode::SINGLE) {
1229 auto pageInfo = FindPageInStack(info.url);
1230 if (pageInfo.second) {
1231 // find page in stack, move postion and update params.
1232 auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1233 if (pagePattern) {
1234 pagePattern->FireOnNewParam(info.params);
1235 }
1236 MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1237 return;
1238 }
1239 auto index = FindPageInRestoreStack(info.url);
1240 if (index != INVALID_PAGE_INDEX) {
1241 // find page in restore page, create page, move position and update params.
1242 RestorePageWithTarget(index, false, info, RestorePageDestination::TOP);
1243 return;
1244 }
1245 }
1246
1247 LoadPage(GenerateNextPageId(), info, true, true, true);
1248 }
1249
ReplaceOhmUrl(const RouterPageInfo & target)1250 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target)
1251 {
1252 RouterOptScope scope(this);
1253 RouterPageInfo info = target;
1254 info.path = info.url + ".js";
1255
1256 PopPage("", false, false);
1257
1258 if (info.routerMode == RouterMode::SINGLE) {
1259 auto pageInfo = FindPageInStack(info.url);
1260 if (pageInfo.second) {
1261 // find page in stack, move postion and update params.
1262 auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
1263 if (pagePattern) {
1264 pagePattern->FireOnNewParam(target.params);
1265 }
1266 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1267 return;
1268 }
1269 auto index = FindPageInRestoreStack(info.url);
1270 if (index != INVALID_PAGE_INDEX) {
1271 // find page in restore page, create page, move position and update params.
1272 RestorePageWithTarget(index, false, info, RestorePageDestination::TOP, false);
1273 return;
1274 }
1275 }
1276
1277 LoadPage(GenerateNextPageId(), info, false, false);
1278 auto container = Container::Current();
1279 CHECK_NULL_VOID(container);
1280 auto pageUrlChecker = container->GetPageUrlChecker();
1281 CHECK_NULL_VOID(pageUrlChecker);
1282 auto taskExecutor = container->GetTaskExecutor();
1283 CHECK_NULL_VOID(taskExecutor);
1284 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1285 TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterReplaceOhmUrl",
1286 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::HIGH));
1287 }
1288
StartReplace(const RouterPageInfo & target)1289 void PageRouterManager::StartReplace(const RouterPageInfo& target)
1290 {
1291 CHECK_RUN_ON(JS);
1292 CleanPageOverlay();
1293 RouterOptScope scope(this);
1294 if (target.url.empty()) {
1295 return;
1296 }
1297 #if !defined(PREVIEW)
1298 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1299 auto loadTask = [weak = AceType::WeakClaim(this), target]() {
1300 auto pageRouterManager = weak.Upgrade();
1301 CHECK_NULL_VOID(pageRouterManager);
1302 pageRouterManager->UpdateSrcPage();
1303 pageRouterManager->ReplaceOhmUrl(target);
1304 };
1305 LoadOhmUrlPage(target.url, std::move(loadTask), target.errorCallback,
1306 "ArkUIPageRouterReplaceOhmUrl", "ArkUIPageRouterReplaceErrorCallback");
1307 return;
1308 }
1309 #endif
1310 if (!manifestParser_) {
1311 return;
1312 }
1313 RouterPageInfo info = target;
1314 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1315 if (info.path.empty()) {
1316 TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartReplace with url: %{public}s", info.url.c_str());
1317 if (info.errorCallback != nullptr) {
1318 info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
1319 }
1320 return;
1321 }
1322 UpdateSrcPage();
1323 DealReplacePage(info);
1324 }
1325
StartBack(const RouterPageInfo & target)1326 void PageRouterManager::StartBack(const RouterPageInfo& target)
1327 {
1328 CleanPageOverlay();
1329 UpdateSrcPage();
1330 if (target.url.empty()) {
1331 size_t pageRouteSize = pageRouterStack_.size();
1332 if (pageRouteSize <= 1) {
1333 if (!restorePageStack_.empty()) {
1334 auto newInfo = RouterPageInfo();
1335 newInfo.params = target.params;
1336 StartRestore(newInfo);
1337 return;
1338 }
1339 TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back start ExitToDesktop");
1340 ExitToDesktop();
1341 return;
1342 }
1343 TAG_LOGI(AceLogTag::ACE_ROUTER, "Router back start PopPage");
1344 PopPage(target.params, true, true);
1345 return;
1346 }
1347
1348 auto pageInfo = FindPageInStack(target.url, true);
1349 if (pageInfo.second) {
1350 // find page in stack, pop to specified index.
1351 RouterPageInfo info = target;
1352 #if !defined(PREVIEW)
1353 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1354 info.path = info.url + ".js";
1355 PopPageToIndex(pageInfo.first, info.params, true, true);
1356 return;
1357 }
1358 #endif
1359 if (!manifestParser_) {
1360 return;
1361 }
1362
1363 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1364 if (info.path.empty()) {
1365 TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartBack with url: %{public}s", info.url.c_str());
1366 return;
1367 }
1368 PopPageToIndex(pageInfo.first, info.params, true, true);
1369 return;
1370 }
1371
1372 auto index = FindPageInRestoreStack(target.url);
1373 if (index == INVALID_PAGE_INDEX) {
1374 return;
1375 }
1376
1377 RestorePageWithTarget(index, true, target, RestorePageDestination::BOTTOM);
1378 }
1379
StartBackToIndex(int32_t index,const std::string & params)1380 void PageRouterManager::StartBackToIndex(int32_t index, const std::string& params)
1381 {
1382 CleanPageOverlay();
1383 if (!manifestParser_) {
1384 return;
1385 }
1386
1387 if (index > static_cast<int32_t>(restorePageStack_.size())) {
1388 PopPageToIndex(index - static_cast<int32_t>(restorePageStack_.size()) - 1, params, true, true);
1389 return;
1390 }
1391
1392 RouterPageInfo info;
1393 info.params = params;
1394 RestorePageWithTarget(index - 1, true, info, RestorePageDestination::BOTTOM);
1395 }
1396
BackCheckAlert(const RouterPageInfo & target)1397 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target)
1398 {
1399 RouterOptScope scope(this);
1400 if (pageRouterStack_.empty()) {
1401 TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not back");
1402 return;
1403 }
1404 auto currentPage = GetCurrentPageNode();
1405 CHECK_NULL_VOID(currentPage);
1406 auto pagePattern = currentPage->GetPattern<PagePattern>();
1407 CHECK_NULL_VOID(pagePattern);
1408 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1409 CHECK_NULL_VOID(pageInfo);
1410 if (pageInfo->GetAlertCallback()) {
1411 ngBackTarget_ = target;
1412 auto pipelineContext = PipelineContext::GetCurrentContext();
1413 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1414 CHECK_NULL_VOID(overlayManager);
1415 overlayManager->ShowDialog(
1416 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1417 return;
1418 }
1419 StartBack(target);
1420 }
1421
BackToIndexCheckAlert(int32_t index,const std::string & params)1422 void PageRouterManager::BackToIndexCheckAlert(int32_t index, const std::string& params)
1423 {
1424 RouterOptScope scope(this);
1425 if (pageRouterStack_.empty()) {
1426 return;
1427 }
1428 RouterPageInfo target = GetPageInfoByIndex(index, params);
1429 auto currentPage = GetCurrentPageNode();
1430 CHECK_NULL_VOID(currentPage);
1431 auto pagePattern = currentPage->GetPattern<PagePattern>();
1432 CHECK_NULL_VOID(pagePattern);
1433 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1434 CHECK_NULL_VOID(pageInfo);
1435 if (pageInfo->GetAlertCallback()) {
1436 ngBackTarget_ = target;
1437 auto pipelineContext = PipelineContext::GetCurrentContext();
1438 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1439 CHECK_NULL_VOID(overlayManager);
1440 overlayManager->ShowDialog(
1441 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1442 return;
1443 }
1444 UpdateSrcPage();
1445 StartBackToIndex(index, params);
1446 }
1447
LoadPage(int32_t pageId,const RouterPageInfo & target,bool needHideLast,bool needTransition,bool)1448 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition,
1449 bool /*isPush*/)
1450 {
1451 ACE_SCOPED_TRACE_COMMERCIAL("load page: %s(id:%d)", target.url.c_str(), pageId);
1452 CHECK_RUN_ON(JS);
1453 auto pageNode = CreatePage(pageId, target);
1454
1455 TaskDependencyManager::GetInstance()->Sync();
1456
1457 if (!pageNode) {
1458 TAG_LOGE(AceLogTag::ACE_ROUTER, "failed to create page in LoadPage");
1459 return;
1460 }
1461
1462 pageRouterStack_.emplace_back(pageNode);
1463 if (!OnPageReady(pageNode, needHideLast, needTransition)) {
1464 pageRouterStack_.pop_back();
1465 TAG_LOGW(AceLogTag::ACE_ROUTER, "LoadPage OnPageReady Failed");
1466 return;
1467 }
1468 AccessibilityEventType type = AccessibilityEventType::CHANGE;
1469 pageNode->OnAccessibilityEvent(type);
1470 TAG_LOGI(AceLogTag::ACE_ROUTER, "LoadPage Success");
1471 }
1472
CreatePage(int32_t pageId,const RouterPageInfo & target)1473 RefPtr<FrameNode> PageRouterManager::CreatePage(int32_t pageId, const RouterPageInfo& target)
1474 {
1475 ACE_SCOPED_TRACE("PageRouterManager::CreatePage");
1476 CHECK_RUN_ON(JS);
1477 TAG_LOGI(AceLogTag::ACE_ROUTER, "Page router manager is creating page[%{public}d]: url: %{public}s path: "
1478 "%{public}s, recoverable: %{public}s, namedRouter: %{public}s", pageId, target.url.c_str(),
1479 target.path.c_str(), (target.recoverable ? "yes" : "no"), (target.isNamedRouterMode ? "yes" : "no"));
1480 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(
1481 pageId, target.url, target.path, target.params, target.recoverable, target.isNamedRouterMode);
1482 auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1483 std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
1484 ResSchedReportScope reportScope("push_page", reportData);
1485 auto pageNode =
1486 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1487 pageNode->SetHostPageId(pageId);
1488 // !!! must push_back first for UpdateRootComponent
1489 pageRouterStack_.emplace_back(pageNode);
1490
1491 if (target.content && !target.content->empty()) {
1492 loadJsByBuffer_(target.content, target.errorCallback, target.params);
1493 } else {
1494 loadJs_(target.path, target.errorCallback);
1495 }
1496 // record full path info of every pageNode
1497 auto pageInfo = pagePattern->GetPageInfo();
1498 if (!pageInfo) {
1499 pageRouterStack_.pop_back();
1500 return nullptr;
1501 }
1502 auto keyInfo = target.url;
1503 if (keyInfo.empty() && manifestParser_) {
1504 auto router = manifestParser_->GetRouter();
1505 if (router) {
1506 keyInfo = router->GetEntry("");
1507 }
1508 }
1509 #if !defined(PREVIEW)
1510 if (keyInfo.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1511 // deal with @bundle url
1512 // @bundle format: @bundle:bundleName/moduleName/pagePath/fileName(without file extension)
1513 // @bundle example: @bundle:com.example.applicationHsp/hsp/ets/pages/Index
1514 // only moduleName and lastPagePath/fileName is needed: hsppages/Index
1515 size_t bundleEndPos = keyInfo.find('/');
1516 size_t moduleStartPos = bundleEndPos + 1;
1517 size_t moduleEndPos = keyInfo.find('/', moduleStartPos);
1518 std::string moduleName = keyInfo.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1519 size_t fileNameStartPos = keyInfo.rfind('/');
1520 size_t pageInfoStartPos = keyInfo.rfind('/', fileNameStartPos - 1);
1521 keyInfo = keyInfo.substr(pageInfoStartPos + 1);
1522 keyInfo = moduleName + keyInfo;
1523 }
1524 #endif
1525 SetPageInfoRouteName(entryPageInfo);
1526 auto pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1527 if (pagePath.empty()) {
1528 auto container = Container::Current();
1529 if (!container) {
1530 pageRouterStack_.pop_back();
1531 return nullptr;
1532 }
1533 auto moduleName = container->GetModuleName();
1534 keyInfo = moduleName + keyInfo;
1535 pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1536 }
1537 pageInfo->SetFullPath(pagePath);
1538
1539 #if defined(PREVIEW)
1540 if (!isComponentPreview_()) {
1541 #endif
1542 auto result = loadNamedRouter_(target.url, target.isNamedRouterMode);
1543 if (!result) {
1544 if (!target.isNamedRouterMode) {
1545 result = updateRootComponent_();
1546 } else if (target.errorCallback) {
1547 target.errorCallback("The named route is not exist.", ERROR_CODE_NAMED_ROUTE_ERROR);
1548 }
1549 }
1550
1551 if (!result) {
1552 TAG_LOGE(AceLogTag::ACE_ROUTER, "Update RootComponent Failed or LoadNamedRouter Failed");
1553 #if !defined(PREVIEW)
1554 if (!target.isNamedRouterMode && target.url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
1555 ThrowError("Load Page Failed: " + target.url, ERROR_CODE_LOAD_PAGE_ERROR);
1556 }
1557 #endif
1558 pageRouterStack_.pop_back();
1559 return nullptr;
1560 }
1561
1562 if (target.isNamedRouterMode) {
1563 if (manifestParser_) {
1564 manifestParser_->SetPagePath(target.url);
1565 } else {
1566 TAG_LOGE(AceLogTag::ACE_ROUTER, "set routeName in manifest failed, manifestParser is null!");
1567 }
1568 }
1569
1570 if (target.errorCallback != nullptr) {
1571 target.errorCallback("", ERROR_CODE_NO_ERROR);
1572 }
1573 #if defined(PREVIEW)
1574 }
1575 #endif
1576
1577 pageRouterStack_.pop_back();
1578 return pageNode;
1579 }
1580
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast,const std::string & entryPoint)1581 UIContentErrorCode PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
1582 int64_t cardId, bool /* isRestore */, bool needHideLast, const std::string& entryPoint)
1583 {
1584 CHECK_RUN_ON(JS);
1585 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
1586 auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1587 auto pageNode =
1588 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1589 pageNode->SetHostPageId(pageId);
1590 pageRouterStack_.emplace_back(pageNode);
1591
1592 if (!loadCard_) {
1593 return UIContentErrorCode::NULL_CARD_CALLBACK;
1594 }
1595 auto result = loadCard_(target.url, cardId, entryPoint);
1596 if (!result) {
1597 pageRouterStack_.pop_back();
1598 return UIContentErrorCode::NULL_CARD_RES;
1599 }
1600
1601 if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
1602 TAG_LOGE(AceLogTag::ACE_ROUTER, "LoadCard OnPageReady Failed");
1603 pageRouterStack_.pop_back();
1604 return UIContentErrorCode::CARD_PAGE_NOT_READY;
1605 }
1606 TAG_LOGI(AceLogTag::ACE_ROUTER, "LoadCard Success");
1607 return UIContentErrorCode::NO_ERRORS;
1608 }
1609
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const RouterPageInfo & target,bool needHideLast,bool forceShowCurrent,bool needTransition)1610 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const RouterPageInfo& target,
1611 bool needHideLast, bool forceShowCurrent, bool needTransition)
1612 {
1613 TAG_LOGI(AceLogTag::ACE_ROUTER, "Move page to front to index: %{public}d", index);
1614 if (target.errorCallback != nullptr) {
1615 target.errorCallback("", ERROR_CODE_NO_ERROR);
1616 }
1617
1618 // update param first.
1619 CHECK_NULL_VOID(pageNode);
1620 auto pagePattern = pageNode->GetPattern<PagePattern>();
1621 CHECK_NULL_VOID(pagePattern);
1622 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1623 CHECK_NULL_VOID(pageInfo);
1624
1625 if (index == static_cast<int32_t>(pageRouterStack_.size()) - 1) {
1626 pageInfo->ReplacePageParams(target.params);
1627 pageInfo->ReplaceRecoverable(target.recoverable);
1628 if (forceShowCurrent) {
1629 pagePattern->ResetPageTransitionEffect();
1630 StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
1631 }
1632 return;
1633 }
1634
1635 auto container = Container::Current();
1636 CHECK_NULL_VOID(container);
1637 auto pipeline = container->GetPipelineContext();
1638 CHECK_NULL_VOID(pipeline);
1639 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1640 auto stageManager = context ? context->GetStageManager() : nullptr;
1641 CHECK_NULL_VOID(stageManager);
1642
1643 // clean pageNode on index position.
1644 auto iter = pageRouterStack_.begin();
1645 std::advance(iter, index);
1646 auto last = pageRouterStack_.erase(iter);
1647 // push pageNode to top.
1648 pageRouterStack_.emplace_back(pageNode);
1649 std::string tempParam = pageInfo->ReplacePageParams(target.params);
1650 bool tempRecoverable = pageInfo->ReplaceRecoverable(target.recoverable);
1651 if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
1652 // restore position and param.
1653 pageRouterStack_.pop_back();
1654 pageRouterStack_.insert(last, pageNode);
1655 if (!tempParam.empty()) {
1656 pageInfo->ReplacePageParams(tempParam);
1657 }
1658 pageInfo->ReplaceRecoverable(tempRecoverable);
1659 }
1660
1661 // update index in pageInfo
1662 int32_t restorePageNumber = static_cast<int32_t>(restorePageStack_.size());
1663 RefreshPageIndex(last, index + restorePageNumber);
1664 }
1665
RefreshPageIndex(std::list<WeakPtr<FrameNode>>::iterator startIter,int32_t startIndex)1666 void PageRouterManager::RefreshPageIndex(std::list<WeakPtr<FrameNode>>::iterator startIter, int32_t startIndex)
1667 {
1668 for (; startIter != pageRouterStack_.end(); ++startIter, ++startIndex) {
1669 auto pageNode = startIter->Upgrade();
1670 if (!pageNode) {
1671 continue;
1672 }
1673 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1674 if (pagePattern) {
1675 pagePattern->GetPageInfo()->SetPageIndex(startIndex + 1);
1676 }
1677 }
1678 }
1679
RefreshAllPageIndex()1680 void PageRouterManager::RefreshAllPageIndex()
1681 {
1682 int32_t restorePageNumber = static_cast<int32_t>(restorePageStack_.size());
1683 RefreshPageIndex(pageRouterStack_.begin(), restorePageNumber);
1684 }
1685
RestorePageWithTarget(int32_t index,bool removeRestorePages,const RouterPageInfo & target,RestorePageDestination dest,bool needTransition)1686 void PageRouterManager::RestorePageWithTarget(int32_t index, bool removeRestorePages,
1687 const RouterPageInfo& target, RestorePageDestination dest, bool needTransition)
1688 {
1689 TAG_LOGI(AceLogTag::ACE_ROUTER, "restore page with target, index: %{public}d, removeRestorePages: %{public}s, "
1690 "target.url: %{public}s, dest: %{public}d", index, removeRestorePages ? "yes" : "no", target.url.c_str(), dest);
1691 RouterPageInfo info = target;
1692 auto iter = restorePageStack_.begin();
1693 std::advance(iter, index);
1694 info.url = iter->url;
1695 info.isNamedRouterMode = iter->isNamedRouter;
1696 info.recoverable = true;
1697 if (!info.errorCallback) {
1698 info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {
1699 TAG_LOGE(AceLogTag::ACE_ROUTER, "restore page with target error: %{public}d, msg: %{public}s",
1700 errorCode, errorMsg.c_str());
1701 };
1702 }
1703 if (removeRestorePages) {
1704 restorePageStack_.erase(iter, restorePageStack_.end());
1705 } else {
1706 restorePageStack_.erase(iter);
1707 }
1708
1709 if (info.isNamedRouterMode) {
1710 if (manifestParser_) {
1711 if (manifestParser_->GetRouter()->GetPagePath(info.url).empty()) {
1712 manifestParser_->SetPagePath(info.url);
1713 }
1714 }
1715 }
1716
1717 if (info.isNamedRouterMode) {
1718 auto callback = [weak = AceType::WeakClaim(this), info, dest, needTransition]() {
1719 auto pageRouterManager = weak.Upgrade();
1720 CHECK_NULL_VOID(pageRouterManager);
1721 pageRouterManager->RestorePageWithTargetInner(info, dest, needTransition);
1722 };
1723 /**
1724 * Always check if the namedRoute page needs to be preloaded.
1725 * @sa PageRouterManager::RestoreRouterStack() & PageRouterManager::GetStackInfo()
1726 */
1727 if (TryPreloadNamedRouter(info.url, std::move(callback))) {
1728 return;
1729 }
1730 }
1731
1732 RestorePageWithTargetInner(info, dest, needTransition);
1733 }
1734
RestorePageWithTargetInner(const RouterPageInfo & target,RestorePageDestination dest,bool needTransition)1735 void PageRouterManager::RestorePageWithTargetInner(
1736 const RouterPageInfo& target, RestorePageDestination dest, bool needTransition)
1737 {
1738 /**
1739 * use 'A' to represent pages in restorePageStack_, use 'B' to represent pages in pageRouterStack_
1740 *
1741 * Case1(RestorePageDestination::TOP), eg: router.pushUrl(options, RouterMode.SINGLE)
1742 * +---+---+---+---+---+ +---+---+---+
1743 * | A | A | A | A | A | | B | B | |
1744 * +---+---+---+---+---+ +---+---+ ^ +
1745 * | |
1746 * +----------------------------+
1747 *
1748 * Case2(RestorePageDestination::BELLOW_TOP), eg:
1749 * router.back()
1750 * +---+---+---+---+---+ +---+---+
1751 * | A | A | A | A | A | | | B |
1752 * +---+---+---+---+---+ + ^ +---+
1753 * | |
1754 * +--------+
1755 *
1756 * router.replacePath({url: 'page/Index'}, RouterMode.SINGLE) (newLifeCycle)
1757 * +---+---+---+---+---+ +---+---+
1758 * | A | A | A | A | A | | B | B |
1759 * +---+---+---+---+---+ +---+---+
1760 * | ^
1761 * | |
1762 * +----------------------+
1763 *
1764 * Case3(RestorePageDestination::BOTTOM), eg: router.back(3), router.back({url: 'page/Index'})
1765 * +---+---+---+---+---+ +---+---+---+
1766 * | A | A | A | A | A | | | B | B |
1767 * +---+---+---+---+---+ + ^ +---+---+
1768 * | |
1769 * +----------------+
1770 *
1771 * Router page restore steps:
1772 * 1. create page
1773 * 2. insert page
1774 * 3. pop page (optional)
1775 * 4. refresh all page's index (optional)
1776 */
1777 std::function<void()> callback = nullptr;
1778 // step3 & step4 pop page, refresh all page's index
1779 if (dest == RestorePageDestination::TOP) {
1780 callback = [weak = WeakClaim(this)] {
1781 auto mgr = weak.Upgrade();
1782 CHECK_NULL_VOID(mgr);
1783 mgr->RefreshAllPageIndex();
1784 };
1785 } else if (dest == RestorePageDestination::BELLOW_TOP) {
1786 callback = [weak = WeakClaim(this), needTransition] {
1787 auto mgr = weak.Upgrade();
1788 CHECK_NULL_VOID(mgr);
1789 mgr->PopPage("", true, needTransition, false);
1790 };
1791 } else if (dest == RestorePageDestination::BOTTOM) {
1792 callback = [weak = WeakClaim(this), params = target.params] {
1793 auto mgr = weak.Upgrade();
1794 CHECK_NULL_VOID(mgr);
1795 mgr->PopPageToIndex(0, params, true, true);
1796 mgr->RefreshAllPageIndex();
1797 };
1798 }
1799
1800 StartRestorePageWithTarget(target, std::move(callback), dest, needTransition);
1801 }
1802
StartRestorePageWithTarget(const RouterPageInfo & target,std::function<void ()> && finishCallback,RestorePageDestination dest,bool needTransition)1803 void PageRouterManager::StartRestorePageWithTarget(const RouterPageInfo& target,
1804 std::function<void()>&& finishCallback, RestorePageDestination dest, bool needTransition)
1805 {
1806 if (target.url.empty()) {
1807 return;
1808 }
1809
1810 CHECK_RUN_ON(JS);
1811 if (inRouterOpt_) {
1812 auto context = PipelineContext::GetCurrentContext();
1813 CHECK_NULL_VOID(context);
1814 context->PostAsyncEvent(
1815 [weak = WeakClaim(this), target, callback = std::move(finishCallback), dest, needTransition]() mutable {
1816 auto router = weak.Upgrade();
1817 CHECK_NULL_VOID(router);
1818 router->StartRestorePageWithTarget(target, std::move(callback), dest, needTransition);
1819 }, "ArkUIPageRouterRestorePageWithTarget", TaskExecutor::TaskType::JS);
1820 return;
1821 }
1822
1823 RouterOptScope scope(this);
1824 RefPtr<FrameNode> pageNode = nullptr;
1825 // step1: create page
1826 if (target.isNamedRouterMode) {
1827 CleanPageOverlay();
1828 pageNode = CreatePage(GenerateNextPageId(), target);
1829 } else {
1830 #if !defined(PREVIEW)
1831 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1832 auto restoreTask = [weak = AceType::WeakClaim(this), target, finishCb = std::move(finishCallback),
1833 dest, needTransition]() mutable {
1834 auto pageRouterManager = weak.Upgrade();
1835 CHECK_NULL_VOID(pageRouterManager);
1836 pageRouterManager->RestoreOhmUrl(target, std::move(finishCb), dest, needTransition);
1837 };
1838 LoadOhmUrlPage(target.url, std::move(restoreTask), target.errorCallback,
1839 "ArkUIPageRouterRestoreOhmUrl", "ArkUIPageRouterRestoreErrorCallback");
1840 return;
1841 }
1842 #endif
1843 if (!manifestParser_) {
1844 return;
1845 }
1846
1847 RouterPageInfo info = target;
1848 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1849 if (info.path.empty()) {
1850 TAG_LOGW(AceLogTag::ACE_ROUTER,
1851 "empty path found in StartRestorePageWithTarget with url: %{public}s", info.url.c_str());
1852 if (info.errorCallback != nullptr) {
1853 info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
1854 }
1855 return;
1856 }
1857
1858 CleanPageOverlay();
1859 pageNode = CreatePage(GenerateNextPageId(), info);
1860 }
1861 if (!pageNode) {
1862 return;
1863 }
1864
1865 // step2: insert page
1866 if (dest == RestorePageDestination::TOP) {
1867 PushPageToTop(pageNode, std::move(finishCallback), needTransition);
1868 } else if (dest == RestorePageDestination::BELLOW_TOP) {
1869 InsertPageBellowTop(pageNode, std::move(finishCallback));
1870 } else if (dest == RestorePageDestination::BOTTOM) {
1871 InsertPageToBottom(pageNode, std::move(finishCallback));
1872 }
1873 }
1874
FlushFrontend()1875 void PageRouterManager::FlushFrontend()
1876 {
1877 auto currentPage = GetCurrentPageNode();
1878 CHECK_NULL_VOID(currentPage);
1879 auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
1880 CHECK_NULL_VOID(customNode);
1881 customNode->FlushReload();
1882 }
1883
PopPage(const std::string & params,bool needShowNext,bool needTransition,bool needReplaceParams)1884 void PageRouterManager::PopPage(
1885 const std::string& params, bool needShowNext, bool needTransition, bool needReplaceParams)
1886 {
1887 CHECK_RUN_ON(JS);
1888 if (pageRouterStack_.empty()) {
1889 TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not pop");
1890 return;
1891 }
1892 if (needShowNext && (pageRouterStack_.size() == 1)) {
1893 TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is only one, can not show next");
1894 return;
1895 }
1896 auto topNode = pageRouterStack_.back();
1897 pageRouterStack_.pop_back();
1898 if (!needShowNext) {
1899 if (!OnPopPage(needShowNext, needTransition)) {
1900 pageRouterStack_.emplace_back(topNode);
1901 }
1902 return;
1903 }
1904
1905 // update param first.
1906 auto nextNode = GetCurrentPageNode();
1907 CHECK_NULL_VOID(nextNode);
1908 auto pagePattern = nextNode->GetPattern<PagePattern>();
1909 CHECK_NULL_VOID(pagePattern);
1910 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1911 CHECK_NULL_VOID(pageInfo);
1912 std::string oldParams;
1913 if (needReplaceParams) {
1914 oldParams = pageInfo->ReplacePageParams(params);
1915 }
1916
1917 if (OnPopPage(needShowNext, needTransition)) {
1918 return;
1919 }
1920 // restore stack and pageParam.
1921 pageRouterStack_.emplace_back(topNode);
1922 if (needReplaceParams) {
1923 pageInfo->ReplacePageParams(oldParams);
1924 }
1925 }
1926
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)1927 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
1928 {
1929 TAG_LOGI(AceLogTag::ACE_ROUTER, "pop page to %{public}d", index);
1930 std::list<WeakPtr<FrameNode>> temp;
1931 std::swap(temp, pageRouterStack_);
1932 auto iter = temp.begin();
1933 for (int32_t current = 0; current <= index; ++current) {
1934 pageRouterStack_.emplace_back(*iter);
1935 ++iter;
1936 }
1937
1938 // update param first.
1939 auto nextNode = GetCurrentPageNode();
1940 CHECK_NULL_VOID(nextNode);
1941 auto pagePattern = nextNode->GetPattern<PagePattern>();
1942 CHECK_NULL_VOID(pagePattern);
1943 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1944 CHECK_NULL_VOID(pageInfo);
1945 auto tempParam = pageInfo->ReplacePageParams(params);
1946 if (OnPopPageToIndex(index, needShowNext, needTransition)) {
1947 return;
1948 }
1949
1950 // restore stack and pageParam.
1951 std::swap(temp, pageRouterStack_);
1952 pageInfo->ReplacePageParams(tempParam);
1953 }
1954
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)1955 bool PageRouterManager::OnPageReady(const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition,
1956 bool isCardRouter, int64_t cardId)
1957 {
1958 Recorder::NodeDataCache::Get().OnPageReady();
1959 auto container = Container::Current();
1960 CHECK_NULL_RETURN(container, false);
1961 RefPtr<PipelineBase> pipeline;
1962 if (isCardRouter) {
1963 auto weak = container->GetCardPipeline(cardId);
1964 pipeline = weak.Upgrade();
1965 CHECK_NULL_RETURN(pipeline, false);
1966 } else {
1967 pipeline = container->GetPipelineContext();
1968 CHECK_NULL_RETURN(pipeline, false);
1969 }
1970
1971 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1972 auto stageManager = context ? context->GetStageManager() : nullptr;
1973 if (stageManager) {
1974 return stageManager->PushPage(pageNode, needHideLast, needTransition);
1975 }
1976 return false;
1977 }
1978
OnPopPage(bool needShowNext,bool needTransition)1979 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
1980 {
1981 auto container = Container::Current();
1982 CHECK_NULL_RETURN(container, false);
1983 auto pipeline = container->GetPipelineContext();
1984 CHECK_NULL_RETURN(pipeline, false);
1985 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1986 auto stageManager = context ? context->GetStageManager() : nullptr;
1987 if (stageManager) {
1988 Recorder::NodeDataCache::Get().OnBeforePagePop();
1989 return stageManager->PopPage(GetCurrentPageNode(), needShowNext, needTransition);
1990 }
1991 return false;
1992 }
1993
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)1994 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
1995 {
1996 auto container = Container::Current();
1997 CHECK_NULL_RETURN(container, false);
1998 auto pipeline = container->GetPipelineContext();
1999 CHECK_NULL_RETURN(pipeline, false);
2000 auto context = DynamicCast<NG::PipelineContext>(pipeline);
2001 auto stageManager = context ? context->GetStageManager() : nullptr;
2002 if (stageManager) {
2003 Recorder::NodeDataCache::Get().OnBeforePagePop();
2004 return stageManager->PopPageToIndex(index, needShowNext, needTransition);
2005 }
2006 return false;
2007 }
2008
OnCleanPageStack()2009 bool PageRouterManager::OnCleanPageStack()
2010 {
2011 auto container = Container::Current();
2012 CHECK_NULL_RETURN(container, false);
2013 auto pipeline = container->GetPipelineContext();
2014 CHECK_NULL_RETURN(pipeline, false);
2015 auto context = DynamicCast<NG::PipelineContext>(pipeline);
2016 auto stageManager = context ? context->GetStageManager() : nullptr;
2017 if (stageManager) {
2018 return stageManager->CleanPageStack();
2019 }
2020 return false;
2021 }
2022
CleanPageOverlay()2023 void PageRouterManager::CleanPageOverlay()
2024 {
2025 auto container = Container::Current();
2026 CHECK_NULL_VOID(container);
2027 auto pipeline = container->GetPipelineContext();
2028 CHECK_NULL_VOID(pipeline);
2029 auto context = DynamicCast<NG::PipelineContext>(pipeline);
2030 CHECK_NULL_VOID(context);
2031 auto overlayManager = context->GetOverlayManager();
2032 CHECK_NULL_VOID(overlayManager);
2033 auto taskExecutor = context->GetTaskExecutor();
2034 CHECK_NULL_VOID(taskExecutor);
2035 auto sharedManager = context->GetSharedOverlayManager();
2036 if (sharedManager) {
2037 sharedManager->StopSharedTransition();
2038 }
2039
2040 overlayManager->RemoveOverlay(true, true);
2041 }
2042
DealReplacePage(const RouterPageInfo & info)2043 void PageRouterManager::DealReplacePage(const RouterPageInfo& info)
2044 {
2045 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2046 ReplacePageInNewLifecycle(info);
2047 return;
2048 }
2049 TAG_LOGI(AceLogTag::ACE_ROUTER,
2050 "router replace in old lifecycle(API version < 12), replace mode: %{public}d, url: %{public}s",
2051 static_cast<int32_t>(info.routerMode), info.url.c_str());
2052 PopPage("", false, false);
2053 if (info.routerMode == RouterMode::SINGLE) {
2054 auto pageInfo = FindPageInStack(info.url);
2055 if (pageInfo.second) {
2056 // find page in stack, move position and update params.
2057 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
2058 return;
2059 }
2060 auto index = FindPageInRestoreStack(info.url);
2061 if (index != INVALID_PAGE_INDEX) {
2062 // find page in restore page, create page, move position and update params.
2063 RestorePageWithTarget(index, false, info, RestorePageDestination::TOP, false);
2064 return;
2065 }
2066 }
2067 LoadPage(GenerateNextPageId(), info, false, false);
2068 }
2069
CheckIndexValid(int32_t index) const2070 bool PageRouterManager::CheckIndexValid(int32_t index) const
2071 {
2072 if (index > GetStackSize() || index <= 0) {
2073 TAG_LOGW(AceLogTag::ACE_ROUTER,
2074 "The index is less than or equal to zero or exceeds the maximum length of the page stack");
2075 return false;
2076 }
2077 return true;
2078 }
2079
CheckOhmUrlValid(const std::string & ohmUrl)2080 bool PageRouterManager::CheckOhmUrlValid(const std::string& ohmUrl)
2081 {
2082 size_t bundleEndPos = ohmUrl.find('/');
2083 std::string bundleName = ohmUrl.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
2084 size_t moduleStartPos = bundleEndPos + 1;
2085 size_t moduleEndPos = ohmUrl.find('/', moduleStartPos);
2086 std::string moduleName = ohmUrl.substr(moduleStartPos, moduleEndPos - moduleStartPos);
2087 auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
2088 Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
2089 return runtime->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmUrl);
2090 }
2091
ThrowError(const std::string & msg,int32_t code)2092 void PageRouterManager::ThrowError(const std::string& msg, int32_t code)
2093 {
2094 auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
2095 Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
2096 runtime->ThrowError(msg, code);
2097 }
2098
GetPageIndex(const WeakPtr<FrameNode> & page)2099 int32_t PageRouterManager::GetPageIndex(const WeakPtr<FrameNode>& page)
2100 {
2101 auto pageNode = page.Upgrade();
2102 CHECK_NULL_RETURN(pageNode, INVALID_PAGE_INDEX);
2103 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
2104 CHECK_NULL_RETURN(pagePattern, INVALID_PAGE_INDEX);
2105 auto ret = pagePattern->GetPageInfo()->GetPageIndex();
2106 // frontend index counts from 1, so need -1 for backend use
2107 return ret == INVALID_PAGE_INDEX ? INVALID_PAGE_INDEX : ret - 1;
2108 }
2109
ReplacePageInNewLifecycle(const RouterPageInfo & info)2110 void PageRouterManager::ReplacePageInNewLifecycle(const RouterPageInfo& info)
2111 {
2112 auto pipelineContext = PipelineContext::GetCurrentContext();
2113 CHECK_NULL_VOID(pipelineContext);
2114 auto stageManager = pipelineContext->GetStageManager();
2115 CHECK_NULL_VOID(stageManager);
2116 TAG_LOGI(AceLogTag::ACE_ROUTER,
2117 "router replace in new lifecycle(API version > 11), replace mode: %{public}d, url: %{public}s",
2118 static_cast<int32_t>(info.routerMode), info.url.c_str());
2119 auto popNode = GetCurrentPageNode();
2120 int32_t popIndex = static_cast<int32_t>(pageRouterStack_.size()) - 1;
2121 bool findPage = false;
2122 if (info.routerMode == RouterMode::SINGLE) {
2123 auto pageInfo = FindPageInStack(info.url);
2124 // haven't find page by named route's name. Try again with its page path.
2125 if (pageInfo.second == nullptr && info.isNamedRouterMode) {
2126 std::string pagePath = Framework::JsiDeclarativeEngine::GetPagePath(info.url);
2127 pageInfo = FindPageInStack(pagePath);
2128 }
2129 if (pageInfo.first == popIndex) {
2130 // replace top self in SINGLE mode, do nothing.
2131 CHECK_NULL_VOID(pageInfo.second);
2132 auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
2133 if (pagePattern) {
2134 pagePattern->FireOnNewParam(info.params);
2135 }
2136 return;
2137 }
2138 if (pageInfo.second) {
2139 // find page in stack, move position and update params.
2140 #if defined(ENABLE_SPLIT_MODE)
2141 stageManager->SetIsNewPageReplacing(true);
2142 #endif
2143 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
2144 #if defined(ENABLE_SPLIT_MODE)
2145 stageManager->SetIsNewPageReplacing(false);
2146 #endif
2147 popIndex = popIndex - 1;
2148 findPage = true;
2149 auto pagePattern = pageInfo.second->GetPattern<PagePattern>();
2150 if (pagePattern) {
2151 pagePattern->FireOnNewParam(info.params);
2152 }
2153 } else {
2154 auto index = FindPageInRestoreStack(info.url);
2155 if (index != INVALID_PAGE_INDEX) {
2156 // find page in restore page, create page, move position and update params.
2157 RestorePageWithTarget(index, false, info, RestorePageDestination::BELLOW_TOP, false);
2158 return;
2159 }
2160 }
2161 }
2162 if (!findPage) {
2163 isNewPageReplacing_ = true;
2164 #if defined(ENABLE_SPLIT_MODE)
2165 stageManager->SetIsNewPageReplacing(true);
2166 #endif
2167 LoadPage(GenerateNextPageId(), info, true, false);
2168 #if defined(ENABLE_SPLIT_MODE)
2169 stageManager->SetIsNewPageReplacing(false);
2170 #endif
2171 isNewPageReplacing_ = false;
2172 }
2173 if (popIndex < 0 || popNode == GetCurrentPageNode() || GetPageIndex(popNode) != popIndex) {
2174 return;
2175 }
2176 auto iter = pageRouterStack_.begin();
2177 std::advance(iter, popIndex);
2178 auto lastIter = pageRouterStack_.erase(iter);
2179 pageRouterStack_.emplace_back(WeakPtr<FrameNode>(AceType::DynamicCast<FrameNode>(popNode)));
2180 popNode->MovePosition(GetLastPageIndex());
2181 for (auto iter = lastIter; iter != pageRouterStack_.end(); ++iter, ++popIndex) {
2182 auto page = iter->Upgrade();
2183 if (!page) {
2184 continue;
2185 }
2186 if (page == popNode) {
2187 // do not change index of page that will be replaced.
2188 continue;
2189 }
2190 auto pagePattern = page->GetPattern<NG::PagePattern>();
2191 pagePattern->GetPageInfo()->SetPageIndex(popIndex + 1);
2192 }
2193 #if defined(ENABLE_SPLIT_MODE)
2194 stageManager->SetIsNewPageReplacing(true);
2195 #endif
2196 PopPage("", false, false);
2197 #if defined(ENABLE_SPLIT_MODE)
2198 stageManager->SetIsNewPageReplacing(false);
2199 #endif
2200 }
2201
RestoreOhmUrl(const RouterPageInfo & target,std::function<void ()> && finishCallback,RestorePageDestination dest,bool needTransition)2202 void PageRouterManager::RestoreOhmUrl(const RouterPageInfo& target, std::function<void()>&& finishCallback,
2203 RestorePageDestination dest, bool needTransition)
2204 {
2205 RouterPageInfo info = target;
2206 info.path = info.url + ".js";
2207 auto pageNode = CreatePage(GenerateNextPageId(), info);
2208 if (!pageNode) {
2209 return;
2210 }
2211
2212 if (dest == RestorePageDestination::TOP) {
2213 PushPageToTop(pageNode, std::move(finishCallback), needTransition);
2214 } else if (dest == RestorePageDestination::BELLOW_TOP) {
2215 InsertPageBellowTop(pageNode, std::move(finishCallback));
2216 } else if (dest == RestorePageDestination::BOTTOM) {
2217 InsertPageToBottom(pageNode, std::move(finishCallback));
2218 }
2219 }
2220
InsertPageBellowTop(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback)2221 void PageRouterManager::InsertPageBellowTop(RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback)
2222 {
2223 auto context = DynamicCast<NG::PipelineContext>(PipelineContext::GetCurrentContext());
2224 auto stageManager = context ? context->GetStageManager() : nullptr;
2225 if (!stageManager) {
2226 return;
2227 }
2228
2229 if (pageRouterStack_.empty()) {
2230 TAG_LOGE(AceLogTag::ACE_ROUTER, "empty stack when insert page bellow top");
2231 return;
2232 }
2233 auto backupStack = pageRouterStack_;
2234 auto it = pageRouterStack_.end();
2235 --it;
2236 pageRouterStack_.insert(it, WeakPtr<FrameNode>(pageNode));
2237
2238 insertPageProcessingType_ = InsertPageProcessingType::INSERT_BELLOW_TOP;
2239 if (!stageManager->InsertPage(pageNode, true)) {
2240 insertPageProcessingType_ = InsertPageProcessingType::NONE;
2241 std::swap(backupStack, pageRouterStack_);
2242 return;
2243 }
2244 insertPageProcessingType_ = InsertPageProcessingType::NONE;
2245
2246 if (finishCallback) {
2247 finishCallback();
2248 }
2249 }
2250
PushPageToTop(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback,bool needTransition)2251 void PageRouterManager::PushPageToTop(
2252 RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback, bool needTransition)
2253 {
2254 pageRouterStack_.emplace_back(pageNode);
2255 if (!OnPageReady(pageNode, true, needTransition)) {
2256 pageRouterStack_.pop_back();
2257 }
2258
2259 if (finishCallback) {
2260 finishCallback();
2261 }
2262 }
2263
InsertPageToBottom(RefPtr<FrameNode> & pageNode,std::function<void ()> && finishCallback)2264 void PageRouterManager::InsertPageToBottom(RefPtr<FrameNode>& pageNode, std::function<void()>&& finishCallback)
2265 {
2266 auto context = DynamicCast<NG::PipelineContext>(PipelineContext::GetCurrentContext());
2267 auto stageManager = context ? context->GetStageManager() : nullptr;
2268 if (!stageManager) {
2269 return;
2270 }
2271
2272 if (pageRouterStack_.empty()) {
2273 TAG_LOGW(AceLogTag::ACE_ROUTER, "empty stack when insert page to bottom");
2274 return;
2275 }
2276 pageRouterStack_.insert(pageRouterStack_.begin(), WeakPtr<FrameNode>(pageNode));
2277
2278 insertPageProcessingType_ = InsertPageProcessingType::INSERT_BOTTOM;
2279 if (!stageManager->InsertPage(pageNode, false)) {
2280 insertPageProcessingType_ = InsertPageProcessingType::NONE;
2281 if (!pageRouterStack_.empty()) {
2282 pageRouterStack_.pop_front();
2283 }
2284 return;
2285 }
2286 insertPageProcessingType_ = InsertPageProcessingType::NONE;
2287
2288 if (finishCallback) {
2289 finishCallback();
2290 }
2291 }
2292
LoadOhmUrlPage(const std::string & url,std::function<void ()> && finishCallback,const std::function<void (const std::string & errorMsg,int32_t errorCode)> & errorCallback,const std::string & finishCallbackTaskName,const std::string & errorCallbackTaskName)2293 void PageRouterManager::LoadOhmUrlPage(const std::string& url, std::function<void()>&& finishCallback,
2294 const std::function<void(const std::string& errorMsg, int32_t errorCode)>& errorCallback,
2295 const std::string& finishCallbackTaskName, const std::string& errorCallbackTaskName)
2296 {
2297 auto container = Container::Current();
2298 CHECK_NULL_VOID(container);
2299 auto pageUrlChecker = container->GetPageUrlChecker();
2300 CHECK_NULL_VOID(pageUrlChecker);
2301 auto instanceId = container->GetInstanceId();
2302 auto taskExecutor = container->GetTaskExecutor();
2303 CHECK_NULL_VOID(taskExecutor);
2304 auto callback = [taskExecutor, instanceId, task = std::move(finishCallback), finishCallbackTaskName]() {
2305 ContainerScope scope(instanceId);
2306 taskExecutor->PostTask(task, TaskExecutor::TaskType::JS, finishCallbackTaskName,
2307 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
2308 };
2309
2310 auto silentInstallErrorCallBack = [errorCb = errorCallback, taskExecutor, instanceId, errorCallbackTaskName](
2311 int32_t errorCode, const std::string& errorMsg) {
2312 if (!errorCb) {
2313 TAG_LOGW(AceLogTag::ACE_ROUTER, "errorCallback is null");
2314 return;
2315 }
2316 ContainerScope scope(instanceId);
2317 taskExecutor->PostTask([errorCb, errorCode, errorMsg]() { errorCb(errorMsg, errorCode); },
2318 TaskExecutor::TaskType::JS, errorCallbackTaskName,
2319 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
2320 };
2321 pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack);
2322 }
2323
SetPageInfoRouteName(const RefPtr<EntryPageInfo> & info)2324 void PageRouterManager::SetPageInfoRouteName(const RefPtr<EntryPageInfo>& info)
2325 {
2326 std::optional<std::string> routeName = std::nullopt;
2327 if (info->IsCreateByNamedRouter()) {
2328 // info->GetPageUrl() represents the name of namedRoute
2329 routeName = info->GetPageUrl();
2330 } else {
2331 auto container = Container::Current();
2332 CHECK_NULL_VOID(container);
2333 // info->GetPageUrl() represents the url of destination page
2334 routeName = Framework::JsiDeclarativeEngine::GetRouteNameByUrl(
2335 info->GetPageUrl(), container->GetBundleName(), container->GetModuleName());
2336 }
2337 info->SetRouteName(routeName);
2338 }
2339
UpdateSrcPage()2340 void PageRouterManager::UpdateSrcPage()
2341 {
2342 auto pipelineContext = PipelineContext::GetCurrentContext();
2343 CHECK_NULL_VOID(pipelineContext);
2344 auto stageManager = pipelineContext->GetStageManager();
2345 CHECK_NULL_VOID(stageManager);
2346 stageManager->SetSrcPage(GetCurrentPageNode());
2347 }
2348 } // namespace OHOS::Ace::NG
2349