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