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