1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/ng/page_router_manager.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <iterator>
21 #include <string>
22
23 #include "base/i18n/localization.h"
24 #include "base/memory/referenced.h"
25 #include "base/ressched/ressched_report.h"
26 #include "base/utils/utils.h"
27 #include "base/perfmonitor/perf_monitor.h"
28 #include "bridge/common/utils/source_map.h"
29 #include "bridge/common/utils/utils.h"
30 #include "bridge/declarative_frontend/ng/entry_page_info.h"
31 #include "bridge/js_frontend/frontend_delegate.h"
32 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
33 #include "core/common/container.h"
34 #include "core/common/recorder/node_data_cache.h"
35 #include "core/common/thread_checker.h"
36 #include "core/components_ng/base/frame_node.h"
37 #include "core/components_ng/base/view_advanced_register.h"
38 #include "core/components_ng/pattern/stage/page_pattern.h"
39 #include "core/components_ng/pattern/stage/stage_manager.h"
40 #include "core/components_v2/inspector/inspector_constants.h"
41 #include "core/pipeline/base/element_register.h"
42 #include "core/pipeline_ng/pipeline_context.h"
43 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
44
45 namespace OHOS::Ace::NG {
46
47 namespace {
48
49 constexpr int32_t BUNDLE_START_POS = 8;
50 constexpr int32_t INVALID_PAGE_INDEX = -1;
51 constexpr int32_t MAX_ROUTER_STACK_SIZE = 32;
52 constexpr int32_t JS_FILE_EXTENSION_LENGTH = 3;
53 constexpr char ETS_PATH[] = "/src/main/ets/";
54 constexpr char DEBUG_PATH[] = "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/";
55 constexpr char NEW_PATH[] = "entry|entry|1.0.0|src/main/ets/";
56 constexpr char TS_SUFFIX[] = ".ts";
57 constexpr char ETS_SUFFIX[] = ".ets";
58
ExitToDesktop()59 void ExitToDesktop()
60 {
61 auto container = Container::Current();
62 CHECK_NULL_VOID(container);
63 auto taskExecutor = container->GetTaskExecutor();
64 CHECK_NULL_VOID(taskExecutor);
65 taskExecutor->PostTask(
66 [] {
67 auto pipeline = PipelineContext::GetCurrentContext();
68 CHECK_NULL_VOID(pipeline);
69 AccessibilityEvent event;
70 event.type = AccessibilityEventType::PAGE_CHANGE;
71 pipeline->SendEventToAccessibility(event);
72 pipeline->Finish(false);
73 },
74 TaskExecutor::TaskType::UI, "ArkUIPageRouterExitToDesktop");
75 }
76
77 } // namespace
78
LoadOhmUrl(const RouterPageInfo & target)79 void PageRouterManager::LoadOhmUrl(const RouterPageInfo& target)
80 {
81 RouterPageInfo info = target;
82 info.path = info.url + ".js";
83 RouterOptScope scope(this);
84 LoadPage(GenerateNextPageId(), info);
85 }
86
RunPage(const std::string & url,const std::string & params)87 void PageRouterManager::RunPage(const std::string& url, const std::string& params)
88 {
89 PerfMonitor::GetPerfMonitor()->SetAppStartStatus();
90 ACE_SCOPED_TRACE("PageRouterManager::RunPage");
91 CHECK_RUN_ON(JS);
92 RouterPageInfo info { url, params };
93 #if !defined(PREVIEW)
94 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
95 auto container = Container::Current();
96 CHECK_NULL_VOID(container);
97 auto pageUrlChecker = container->GetPageUrlChecker();
98 CHECK_NULL_VOID(pageUrlChecker);
99 auto instanceId = container->GetInstanceId();
100 auto taskExecutor = container->GetTaskExecutor();
101 CHECK_NULL_VOID(taskExecutor);
102 info.errorCallback = [](const std::string& errorMsg, int32_t errorCode) {};
103 auto callback = [weak = AceType::WeakClaim(this), info, taskExecutor, instanceId]() {
104 ContainerScope scope(instanceId);
105 auto pageRouterManager = weak.Upgrade();
106 CHECK_NULL_VOID(pageRouterManager);
107 taskExecutor->PostTask(
108 [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
109 TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrl");
110 };
111
112 auto silentInstallErrorCallBack = [taskExecutor, instanceId](int32_t errorCode, const std::string& errorMsg) {
113 ContainerScope scope(instanceId);
114 taskExecutor->PostTask(
115 [errorCode, errorMsg]() {
116 LOGW("Run page error = %{public}d, errorMsg = %{public}s", errorCode, errorMsg.c_str());
117 },
118 TaskExecutor::TaskType::JS, "ArkUIPageRouterErrorLog");
119 };
120
121 pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack);
122 return;
123 }
124 #endif
125 if (!info.url.empty()) {
126 info.path = manifestParser_->GetRouter()->GetPagePath(url);
127 if (info.path.empty()) {
128 return;
129 }
130 } else {
131 info.path = manifestParser_->GetRouter()->GetEntry();
132 info.url = manifestParser_->GetRouter()->GetEntry("");
133 }
134 RouterOptScope scope(this);
135 LoadPage(GenerateNextPageId(), info);
136 }
137
RunPage(const std::shared_ptr<std::vector<uint8_t>> & content,const std::string & params)138 void PageRouterManager::RunPage(const std::shared_ptr<std::vector<uint8_t>>& content, const std::string& params)
139 {
140 CHECK_RUN_ON(JS);
141 RouterPageInfo info;
142 info.content = content;
143 info.params = params;
144
145 #if !defined(PREVIEW)
146 auto container = Container::Current();
147 CHECK_NULL_VOID(container);
148 auto instanceId = container->GetInstanceId();
149 auto taskExecutor = container->GetTaskExecutor();
150 CHECK_NULL_VOID(taskExecutor);
151 ContainerScope scope(instanceId);
152 auto pageRouterManager = AceType::Claim(this);
153 CHECK_NULL_VOID(pageRouterManager);
154 taskExecutor->PostTask(
155 [pageRouterManager, info]() { pageRouterManager->LoadOhmUrl(info); },
156 TaskExecutor::TaskType::JS, "ArkUIPageRouterLoadOhmUrlContent");
157 #endif
158 }
159
RunPageByNamedRouter(const std::string & name,const std::string & params)160 void PageRouterManager::RunPageByNamedRouter(const std::string& name, const std::string& params)
161 {
162 RouterPageInfo info { name, params };
163 info.isNamedRouterMode = true;
164 RouterOptScope scope(this);
165 LoadPage(GenerateNextPageId(), info);
166 }
167
RunCard(const std::string & url,const std::string & params,int64_t cardId,const std::string & entryPoint)168 UIContentErrorCode PageRouterManager::RunCard(
169 const std::string& url, const std::string& params, int64_t cardId, const std::string& entryPoint)
170 {
171 CHECK_RUN_ON(JS);
172 RouterPageInfo info { url };
173 #ifndef PREVIEW
174 if (!info.url.empty()) {
175 info.path = manifestParser_->GetRouter()->GetPagePath(url);
176 } else {
177 info.path = manifestParser_->GetRouter()->GetEntry();
178 info.url = manifestParser_->GetRouter()->GetEntry("");
179 }
180 #endif
181 return LoadCard(0, info, params, cardId, false, true, entryPoint);
182 }
183
Push(const RouterPageInfo & target)184 void PageRouterManager::Push(const RouterPageInfo& target)
185 {
186 CHECK_RUN_ON(JS);
187 if (inRouterOpt_) {
188 auto context = PipelineContext::GetCurrentContext();
189 CHECK_NULL_VOID(context);
190 context->PostAsyncEvent(
191 [weak = WeakClaim(this), target]() {
192 auto router = weak.Upgrade();
193 CHECK_NULL_VOID(router);
194 router->Push(target);
195 },
196 "ArkUIPageRouterPush", TaskExecutor::TaskType::JS);
197 return;
198 }
199 RouterOptScope scope(this);
200 StartPush(target);
201 }
202
PushNamedRoute(const RouterPageInfo & target)203 void PageRouterManager::PushNamedRoute(const RouterPageInfo& target)
204 {
205 CHECK_RUN_ON(JS);
206 if (inRouterOpt_) {
207 auto context = PipelineContext::GetCurrentContext();
208 CHECK_NULL_VOID(context);
209 context->PostAsyncEvent(
210 [weak = WeakClaim(this), target]() {
211 auto router = weak.Upgrade();
212 CHECK_NULL_VOID(router);
213 router->PushNamedRoute(target);
214 },
215 "ArkUIPageRouterPushNamedRoute", TaskExecutor::TaskType::JS);
216 return;
217 }
218 RouterOptScope scope(this);
219 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
220 LOGW("router stack size is larger than max size 32.");
221 if (target.errorCallback != nullptr) {
222 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
223 }
224 return;
225 }
226 CleanPageOverlay();
227 if (target.routerMode == RouterMode::SINGLE) {
228 auto PageInfoByUrl = FindPageInStackByRouteName(target.url);
229 if (PageInfoByUrl.second) {
230 // find page in stack, move postion and update params.
231 MovePageToFront(PageInfoByUrl.first, PageInfoByUrl.second, target, true);
232 return;
233 }
234 }
235 RouterPageInfo info = target;
236 info.isNamedRouterMode = true;
237 LoadPage(GenerateNextPageId(), info, true, true, true);
238 }
239
Replace(const RouterPageInfo & target)240 void PageRouterManager::Replace(const RouterPageInfo& target)
241 {
242 CHECK_RUN_ON(JS);
243 if (inRouterOpt_) {
244 auto context = PipelineContext::GetCurrentContext();
245 CHECK_NULL_VOID(context);
246 context->PostAsyncEvent(
247 [weak = WeakClaim(this), target]() {
248 auto router = weak.Upgrade();
249 CHECK_NULL_VOID(router);
250 router->Replace(target);
251 },
252 "ArkUIPageRouterReplace", TaskExecutor::TaskType::JS);
253 return;
254 }
255 RouterOptScope scope(this);
256 StartReplace(target);
257 }
258
ReplaceNamedRoute(const RouterPageInfo & target)259 void PageRouterManager::ReplaceNamedRoute(const RouterPageInfo& target)
260 {
261 CHECK_RUN_ON(JS);
262 if (inRouterOpt_) {
263 auto context = PipelineContext::GetCurrentContext();
264 CHECK_NULL_VOID(context);
265 context->PostAsyncEvent(
266 [weak = WeakClaim(this), target]() {
267 auto router = weak.Upgrade();
268 CHECK_NULL_VOID(router);
269 router->ReplaceNamedRoute(target);
270 },
271 "ArkUIPageRouterReplaceNamedRoute", TaskExecutor::TaskType::JS);
272 return;
273 }
274 RouterOptScope scope(this);
275 CleanPageOverlay();
276 RouterPageInfo info = target;
277 info.isNamedRouterMode = true;
278 DealReplacePage(info);
279 }
280
BackWithTarget(const RouterPageInfo & target)281 void PageRouterManager::BackWithTarget(const RouterPageInfo& target)
282 {
283 CHECK_RUN_ON(JS);
284 LOGI("Router back path = %{private}s", target.url.c_str());
285 if (inRouterOpt_) {
286 auto context = PipelineContext::GetCurrentContext();
287 CHECK_NULL_VOID(context);
288 context->PostAsyncEvent(
289 [weak = WeakClaim(this), target]() {
290 auto router = weak.Upgrade();
291 CHECK_NULL_VOID(router);
292 router->BackWithTarget(target);
293 },
294 "ArkUIPageRouterBackWithTarget", TaskExecutor::TaskType::JS);
295 return;
296 }
297 RouterOptScope scope(this);
298 BackCheckAlert(target);
299 }
300
BackToIndexWithTarget(int32_t index,const std::string & params)301 void PageRouterManager::BackToIndexWithTarget(int32_t index, const std::string& params)
302 {
303 CHECK_RUN_ON(JS);
304 if (!CheckIndexValid(index)) {
305 return;
306 }
307 if (inRouterOpt_) {
308 auto context = PipelineContext::GetCurrentContext();
309 CHECK_NULL_VOID(context);
310 context->PostAsyncEvent(
311 [weak = WeakClaim(this), index, params]() {
312 auto router = weak.Upgrade();
313 CHECK_NULL_VOID(router);
314 router->BackToIndexWithTarget(index, params);
315 },
316 "ArkUIPageRouterBackToIndex", TaskExecutor::TaskType::JS);
317 return;
318 }
319 RouterOptScope scope(this);
320 BackToIndexCheckAlert(index, params);
321 }
322
Clear()323 void PageRouterManager::Clear()
324 {
325 CHECK_RUN_ON(JS);
326 if (inRouterOpt_) {
327 auto context = PipelineContext::GetCurrentContext();
328 CHECK_NULL_VOID(context);
329 context->PostAsyncEvent(
330 [weak = WeakClaim(this)]() {
331 auto router = weak.Upgrade();
332 CHECK_NULL_VOID(router);
333 router->Clear();
334 },
335 "ArkUIPageRouterClear", TaskExecutor::TaskType::JS);
336 return;
337 }
338 RouterOptScope scope(this);
339 StartClean();
340 }
341
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)342 void PageRouterManager::EnableAlertBeforeBackPage(const std::string& message, std::function<void(int32_t)>&& callback)
343 {
344 auto currentPage = GetCurrentPageNode();
345 CHECK_NULL_VOID(currentPage);
346 auto pagePattern = currentPage->GetPattern<PagePattern>();
347 CHECK_NULL_VOID(pagePattern);
348 auto pageInfo = pagePattern->GetPageInfo();
349 CHECK_NULL_VOID(pageInfo);
350
351 DialogProperties dialogProperties = {
352 .content = message,
353 .autoCancel = false,
354 .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
355 { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
356 .onSuccess =
357 [weak = AceType::WeakClaim(this), weakPageInfo = AceType::WeakClaim(AceType::RawPtr(pageInfo))](
358 int32_t successType, int32_t successIndex) {
359 auto pageInfo = weakPageInfo.Upgrade();
360 if (pageInfo && pageInfo->GetAlertCallback() && !successType) {
361 pageInfo->GetAlertCallback()(successIndex);
362 if (successIndex) {
363 auto router = weak.Upgrade();
364 CHECK_NULL_VOID(router);
365 router->StartBack(router->ngBackTarget_);
366 }
367 }
368 },
369 };
370
371 pageInfo->SetDialogProperties(dialogProperties);
372 pageInfo->SetAlertCallback(std::move(callback));
373 }
374
DisableAlertBeforeBackPage()375 void PageRouterManager::DisableAlertBeforeBackPage()
376 {
377 if (pageRouterStack_.empty()) {
378 return;
379 }
380 auto currentPage = GetCurrentPageNode();
381 CHECK_NULL_VOID(currentPage);
382 auto pagePattern = currentPage->GetPattern<PagePattern>();
383 CHECK_NULL_VOID(pagePattern);
384 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
385 CHECK_NULL_VOID(pageInfo);
386 pageInfo->SetAlertCallback(nullptr);
387 }
388
StartClean()389 void PageRouterManager::StartClean()
390 {
391 if (pageRouterStack_.size() <= 1) {
392 return;
393 }
394 std::list<WeakPtr<FrameNode>> temp;
395 std::swap(temp, pageRouterStack_);
396 pageRouterStack_.emplace_back(temp.back());
397 if (!OnCleanPageStack()) {
398 std::swap(temp, pageRouterStack_);
399 } else {
400 auto pageNode = pageRouterStack_.back().Upgrade();
401 if (!pageNode) {
402 return;
403 }
404 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
405 if (pagePattern) {
406 // the size of pageRouterStack_ should be 1
407 pagePattern->GetPageInfo()->SetPageIndex(static_cast<int32_t>(pageRouterStack_.size()));
408 }
409 }
410 }
411
Pop()412 bool PageRouterManager::Pop()
413 {
414 CHECK_RUN_ON(JS);
415 if (inRouterOpt_) {
416 TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop is in routeropt");
417 return false;
418 }
419 RouterOptScope scope(this);
420 return StartPop();
421 }
422
StartPop()423 bool PageRouterManager::StartPop()
424 {
425 CHECK_RUN_ON(JS);
426 auto currentPage = GetCurrentPageNode();
427 CHECK_NULL_RETURN(currentPage, false);
428 auto pagePattern = currentPage->GetPattern<PagePattern>();
429 CHECK_NULL_RETURN(pagePattern, false);
430 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
431 CHECK_NULL_RETURN(pageInfo, false);
432 if (pageInfo->GetAlertCallback()) {
433 TAG_LOGI(AceLogTag::ACE_ROUTER, "pop alert check start");
434 BackCheckAlert(RouterPageInfo());
435 return true;
436 }
437
438 if (pageRouterStack_.size() <= 1) {
439 if (!restorePageStack_.empty()) {
440 StartRestore(RouterPageInfo());
441 return true;
442 }
443 // the last page.
444 return false;
445 }
446
447 // pop top page in page stack
448 auto preWeakNode = pageRouterStack_.back();
449 pageRouterStack_.pop_back();
450
451 // clean prev top page params
452 currentPage = GetCurrentPageNode();
453 CHECK_NULL_RETURN(currentPage, false);
454 pagePattern = currentPage->GetPattern<PagePattern>();
455 CHECK_NULL_RETURN(pagePattern, false);
456 pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
457 CHECK_NULL_RETURN(pageInfo, false);
458 std::string params = pageInfo->GetPageParams();
459 pageInfo->ReplacePageParams("");
460
461 // do pop page
462 if (!OnPopPage(true, true)) {
463 pageRouterStack_.emplace_back(preWeakNode);
464 pageInfo->ReplacePageParams(params);
465 return false;
466 }
467 return true;
468 }
469
StartRestore(const RouterPageInfo & target)470 void PageRouterManager::StartRestore(const RouterPageInfo& target)
471 {
472 RouterPageInfo info = target;
473 auto tempStack = restorePageStack_;
474 if (target.url.empty()) {
475 info.url = tempStack.back();
476 tempStack.pop_back();
477 } else {
478 info.url = target.url;
479 while (!tempStack.empty() && tempStack.back() != info.url) {
480 tempStack.pop_back();
481 }
482 if (tempStack.empty()) {
483 return;
484 }
485 tempStack.pop_back();
486 }
487
488 restorePageStack_ = tempStack;
489 StartClean();
490 PopPage("", false, false);
491 StartPush(info);
492 }
493
GetStackSize() const494 int32_t PageRouterManager::GetStackSize() const
495 {
496 CHECK_RUN_ON(JS);
497 auto realSize = isNewPageReplacing_ ? pageRouterStack_.size() - 1 : pageRouterStack_.size();
498 return static_cast<int32_t>(realSize);
499 }
500
GetPageInfoByIndex(int32_t index,const std::string & params)501 RouterPageInfo PageRouterManager::GetPageInfoByIndex(int32_t index, const std::string& params)
502 {
503 RouterPageInfo emptyForReturn;
504 if (!CheckIndexValid(index) &&
505 index != static_cast<int32_t>(pageRouterStack_.size() + 1) /* in case the page is on popping */) {
506 return emptyForReturn;
507 }
508 std::string url;
509 int32_t counter = 1;
510 for (const auto& iter : pageRouterStack_) {
511 if (counter == index) {
512 auto pageNode = iter.Upgrade();
513 CHECK_NULL_RETURN(pageNode, emptyForReturn);
514 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
515 CHECK_NULL_RETURN(pagePattern, emptyForReturn);
516 auto pageInfo = pagePattern->GetPageInfo();
517 CHECK_NULL_RETURN(pageInfo, emptyForReturn);
518 return NG::RouterPageInfo({ pageInfo->GetPageUrl(), params });
519 }
520 counter++;
521 }
522
523 // in case the page is on popping
524 auto pipelineContext = PipelineContext::GetCurrentContext();
525 CHECK_NULL_RETURN(pipelineContext, emptyForReturn);
526 auto stageManager = pipelineContext->GetStageManager();
527 CHECK_NULL_RETURN(stageManager, emptyForReturn);
528 auto popPage = stageManager->GetLastPage();
529 CHECK_NULL_RETURN(popPage, emptyForReturn);
530 auto pagePattern = popPage->GetPattern<NG::PagePattern>();
531 CHECK_NULL_RETURN(pagePattern, emptyForReturn);
532 auto pageInfo = pagePattern->GetPageInfo();
533 // make sure the last page is the one with 'index'
534 if (pageInfo && pageInfo->GetPageIndex() == index) {
535 return NG::RouterPageInfo({ pageInfo->GetPageUrl(), params });
536 }
537 return emptyForReturn;
538 }
539
GetState(int32_t & index,std::string & name,std::string & path)540 void PageRouterManager::GetState(int32_t& index, std::string& name, std::string& path)
541 {
542 CHECK_RUN_ON(JS);
543 if (pageRouterStack_.empty()) {
544 return;
545 }
546 index = static_cast<int32_t>(pageRouterStack_.size());
547 if (isNewPageReplacing_) {
548 if (index <= 1) {
549 TAG_LOGD(AceLogTag::ACE_ROUTER, "router stack size invalid while replacing");
550 } else {
551 index = index - 1;
552 }
553 }
554 auto pageNode = GetCurrentPageNode();
555 CHECK_NULL_VOID(pageNode);
556 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
557 CHECK_NULL_VOID(pagePattern);
558 auto pageInfo = pagePattern->GetPageInfo();
559 CHECK_NULL_VOID(pageInfo);
560 auto url = pageInfo->GetPageUrl();
561 auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
562 if (!pagePath.empty()) {
563 url = pagePath;
564 }
565 auto pos = url.rfind(".js");
566 if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
567 url = url.substr(0, pos);
568 }
569 pos = url.rfind("/");
570 if (pos != std::string::npos) {
571 name = url.substr(pos + 1);
572 path = url.substr(0, pos + 1);
573 }
574 if (name.size() == 0) {
575 name = "index";
576 }
577 if (path.size() == 0) {
578 path = "/" + url;
579 }
580 }
581
GetStateByIndex(int32_t index,std::string & name,std::string & path,std::string & params)582 void PageRouterManager::GetStateByIndex(int32_t index, std::string& name, std::string& path, std::string& params)
583 {
584 CHECK_RUN_ON(JS);
585 if (!CheckIndexValid(index) &&
586 index != static_cast<int32_t>(pageRouterStack_.size() + 1) /* in case the page is on popping */) {
587 return;
588 }
589
590 int32_t counter = 1;
591 for (const auto& iter : pageRouterStack_) {
592 if (counter == index) {
593 auto pageNode = iter.Upgrade();
594 CHECK_NULL_VOID(pageNode);
595 GetPageNameAndPath(pageNode, name, path);
596 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
597 CHECK_NULL_VOID(pagePattern);
598 auto pageInfo = DynamicCast<NG::EntryPageInfo>(pagePattern->GetPageInfo());
599 CHECK_NULL_VOID(pageInfo);
600 params = pageInfo->GetPageParams();
601 return;
602 }
603 counter++;
604 }
605
606 // in case the page is on popping
607 auto pipelineContext = PipelineContext::GetCurrentContext();
608 CHECK_NULL_VOID(pipelineContext);
609 auto stageManager = pipelineContext->GetStageManager();
610 CHECK_NULL_VOID(stageManager);
611 auto popPage = stageManager->GetLastPage();
612 CHECK_NULL_VOID(popPage);
613 auto pagePattern = popPage->GetPattern<NG::PagePattern>();
614 CHECK_NULL_VOID(pagePattern);
615 auto pageInfo = pagePattern->GetPageInfo();
616 // make sure the last page is the one with 'index'
617 if (pageInfo && pageInfo->GetPageIndex() == index) {
618 GetPageNameAndPath(popPage, name, path);
619 auto entryPageInfo = DynamicCast<NG::EntryPageInfo>(pageInfo);
620 CHECK_NULL_VOID(entryPageInfo);
621 params = entryPageInfo->GetPageParams();
622 }
623 }
624
GetStateByUrl(std::string & url,std::vector<Framework::StateInfo> & stateArray)625 void PageRouterManager::GetStateByUrl(std::string& url, std::vector<Framework::StateInfo>& stateArray)
626 {
627 CHECK_RUN_ON(JS);
628 int32_t counter = 1;
629 Framework::StateInfo stateInfo;
630 for (auto& iter : pageRouterStack_) {
631 auto pageNode = iter.Upgrade();
632 CHECK_NULL_VOID(pageNode);
633 auto pagePattern = pageNode->GetPattern<PagePattern>();
634 CHECK_NULL_VOID(pagePattern);
635 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
636 CHECK_NULL_VOID(pageInfo);
637 std::string tempUrl;
638 if (pageInfo->GetPageUrl() == url) {
639 stateInfo.params = pageInfo->GetPageParams();
640 stateInfo.index = counter;
641 auto pos = url.rfind(".js");
642 if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
643 tempUrl = url.substr(0, pos);
644 }
645 tempUrl = url;
646 auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
647 if (!pagePath.empty()) {
648 tempUrl = pagePath;
649 }
650 pos = tempUrl.rfind("/");
651 if (pos != std::string::npos) {
652 stateInfo.name = tempUrl.substr(pos + 1);
653 stateInfo.path = tempUrl.substr(0, pos + 1);
654 }
655 if (stateInfo.name.size() == 0) {
656 stateInfo.name = "index";
657 }
658 if (stateInfo.path.size() == 0) {
659 stateInfo.path = "/" + tempUrl;
660 }
661 stateArray.emplace_back(stateInfo);
662 }
663 counter++;
664 }
665 }
666
GetPageNameAndPath(const RefPtr<FrameNode> & pageNode,std::string & name,std::string & path)667 void PageRouterManager::GetPageNameAndPath(const RefPtr<FrameNode>& pageNode, std::string& name, std::string& path)
668 {
669 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
670 CHECK_NULL_VOID(pagePattern);
671 auto pageInfo = pagePattern->GetPageInfo();
672 CHECK_NULL_VOID(pageInfo);
673 auto url = pageInfo->GetPageUrl();
674 auto pagePath = Framework::JsiDeclarativeEngine::GetPagePath(url);
675 if (!pagePath.empty()) {
676 url = pagePath;
677 }
678 auto pos = url.rfind(".js");
679 if (pos == url.length() - JS_FILE_EXTENSION_LENGTH) {
680 url = url.substr(0, pos);
681 }
682 pos = url.rfind("/");
683 if (pos != std::string::npos) {
684 name = url.substr(pos + 1);
685 path = url.substr(0, pos + 1);
686 }
687 if (name.size() == 0) {
688 name = "index";
689 }
690 if (path.size() == 0) {
691 path = "/" + url;
692 }
693 }
694
GetParams() const695 std::string PageRouterManager::GetParams() const
696 {
697 CHECK_RUN_ON(JS);
698 if (pageRouterStack_.empty()) {
699 return "";
700 }
701 auto pageNode = pageRouterStack_.back().Upgrade();
702 CHECK_NULL_RETURN(pageNode, "");
703 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
704 CHECK_NULL_RETURN(pagePattern, "");
705 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
706 CHECK_NULL_RETURN(pageInfo, "");
707 return pageInfo->GetPageParams();
708 }
709
GetIndexByUrl(const std::string & url) const710 int32_t PageRouterManager::GetIndexByUrl(const std::string& url) const
711 {
712 int32_t index = 0;
713 for (auto iter : pageRouterStack_) {
714 auto pageNode = iter.Upgrade();
715 if (!pageNode) {
716 continue;
717 }
718 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
719 auto localUrl = pagePattern->GetPageInfo()->GetPageUrl();
720 if (localUrl == url) {
721 return index;
722 }
723 ++index;
724 }
725 return INVALID_PAGE_INDEX;
726 }
727
GetCurrentPageUrl()728 std::string PageRouterManager::GetCurrentPageUrl()
729 {
730 CHECK_RUN_ON(JS);
731 if (pageRouterStack_.empty()) {
732 return "";
733 }
734 auto pageNode = GetCurrentPageNode();
735 CHECK_NULL_RETURN(pageNode, "");
736 auto pagePattern = pageNode->GetPattern<PagePattern>();
737 CHECK_NULL_RETURN(pagePattern, "");
738 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
739 CHECK_NULL_RETURN(entryPageInfo, "");
740 return entryPageInfo->GetPagePath();
741 }
742
743 // Get the currently running JS page information in NG structure.
GetCurrentPageSourceMap(const RefPtr<AssetManager> & assetManager)744 RefPtr<Framework::RevSourceMap> PageRouterManager::GetCurrentPageSourceMap(const RefPtr<AssetManager>& assetManager)
745 {
746 CHECK_RUN_ON(JS);
747 if (pageRouterStack_.empty()) {
748 return nullptr;
749 }
750 auto pageNode = GetCurrentPageNode();
751 CHECK_NULL_RETURN(pageNode, nullptr);
752 auto pagePattern = pageNode->GetPattern<PagePattern>();
753 CHECK_NULL_RETURN(pagePattern, nullptr);
754 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
755 CHECK_NULL_RETURN(entryPageInfo, nullptr);
756 auto pageMap = entryPageInfo->GetPageMap();
757 if (pageMap) {
758 return pageMap;
759 }
760 // initialize page map.
761 std::string jsSourceMap;
762 // stage mode
763 auto container = Container::Current();
764 CHECK_NULL_RETURN(container, nullptr);
765 if (container->IsUseStageModel()) {
766 auto pagePath = entryPageInfo->GetPagePath();
767 auto moduleName = container->GetModuleName();
768 std::string judgePath = "";
769 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
770 judgePath = DEBUG_PATH + moduleName + ETS_PATH +
771 pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
772 } else {
773 judgePath = moduleName + ETS_PATH +
774 pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + ETS_SUFFIX;
775 }
776 if (Framework::GetAssetContentImpl(assetManager, "sourceMaps.map", jsSourceMap)) {
777 auto jsonPages = JsonUtil::ParseJsonString(jsSourceMap);
778 auto child = jsonPages->GetChild();
779 if (!child->GetValue("entry-package-info")->IsNull()) {
780 judgePath = NEW_PATH + pagePath.substr(0, pagePath.size() - JS_FILE_EXTENSION_LENGTH) + TS_SUFFIX;
781 }
782 auto jsonPage = jsonPages->GetValue(judgePath)->ToString();
783 auto stagePageMap = MakeRefPtr<Framework::RevSourceMap>();
784 stagePageMap->Init(jsonPage);
785 entryPageInfo->SetPageMap(stagePageMap);
786 return stagePageMap;
787 }
788 } else {
789 if (Framework::GetAssetContentImpl(assetManager, entryPageInfo->GetPagePath() + ".map", jsSourceMap)) {
790 auto faPageMap = MakeRefPtr<Framework::RevSourceMap>();
791 faPageMap->Init(jsSourceMap);
792 entryPageInfo->SetPageMap(faPageMap);
793 return faPageMap;
794 }
795 }
796 return nullptr;
797 }
798
GetStackInfo()799 std::unique_ptr<JsonValue> PageRouterManager::GetStackInfo()
800 {
801 auto jsonRouterStack = JsonUtil::CreateArray(true);
802 auto restoreIter = restorePageStack_.begin();
803 while (restoreIter != restorePageStack_.end()) {
804 auto jsonItem = JsonUtil::Create(true);
805 jsonItem->Put("url", restoreIter->c_str());
806 jsonRouterStack->Put(jsonItem);
807 ++restoreIter;
808 }
809 auto iter = pageRouterStack_.begin();
810 while (iter != pageRouterStack_.end()) {
811 auto pageNode = iter->Upgrade();
812 CHECK_NULL_RETURN(pageNode, jsonRouterStack);
813 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
814 CHECK_NULL_RETURN(pagePattern, jsonRouterStack);
815 auto pageInfo = pagePattern->GetPageInfo();
816 CHECK_NULL_RETURN(pageInfo, jsonRouterStack);
817 auto url = pageInfo->GetPageUrl();
818 auto jsonItem = JsonUtil::Create(true);
819 jsonItem->Put("url", url.c_str());
820 jsonRouterStack->Put(jsonItem);
821 ++iter;
822 }
823 return jsonRouterStack;
824 }
825
RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)826 std::pair<std::string, UIContentErrorCode> PageRouterManager::RestoreRouterStack(std::unique_ptr<JsonValue> stackInfo)
827 {
828 if (!stackInfo->IsValid() || !stackInfo->IsArray()) {
829 return std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER);
830 }
831 int32_t stackSize = stackInfo->GetArraySize();
832 if (stackSize < 1) {
833 return std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER);
834 }
835
836 auto container = Container::Current();
837 CHECK_NULL_RETURN(container, std::make_pair("", UIContentErrorCode::NULL_POINTER));
838 auto pipeline = container->GetPipelineContext();
839 CHECK_NULL_RETURN(pipeline, std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER));
840 auto context = DynamicCast<NG::PipelineContext>(pipeline);
841 auto stageManager = context ? context->GetStageManager() : nullptr;
842 CHECK_NULL_RETURN(stageManager, std::make_pair("", UIContentErrorCode::WRONG_PAGE_ROUTER));
843
844 for (int32_t index = 0; index < stackSize - 1; ++index) {
845 std::string url = stackInfo->GetArrayItem(index)->GetValue("url")->ToString();
846 // remove 2 useless character, as "XXX" to XXX
847 url = url.substr(1, url.size() - 2);
848 restorePageStack_.emplace_back(url);
849 }
850 std::string startUrl = stackInfo->GetArrayItem(stackSize - 1)->GetValue("url")->ToString();
851 // remove 2 useless character, as "XXX" to XXX
852 return std::make_pair(startUrl.substr(1, startUrl.size() - 2), UIContentErrorCode::NO_ERRORS);
853 }
854
GenerateNextPageId()855 int32_t PageRouterManager::GenerateNextPageId()
856 {
857 return ++pageId_;
858 }
859
FindPageInStack(const std::string & url,bool needIgnoreBegin)860 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStack(const std::string& url, bool needIgnoreBegin)
861 {
862 auto iter = std::find_if(needIgnoreBegin ? ++pageRouterStack_.rbegin() : pageRouterStack_.rbegin(),
863 pageRouterStack_.rend(), [url](const WeakPtr<FrameNode>& item) {
864 auto pageNode = item.Upgrade();
865 CHECK_NULL_RETURN(pageNode, false);
866 auto pagePattern = pageNode->GetPattern<PagePattern>();
867 CHECK_NULL_RETURN(pagePattern, false);
868 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
869 CHECK_NULL_RETURN(entryPageInfo, false);
870 return entryPageInfo->GetPageUrl() == url;
871 });
872 if (iter == pageRouterStack_.rend()) {
873 return { -1, nullptr };
874 }
875 // Returns to the forward position.
876 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
877 }
878
FindPageInStackByRouteName(const std::string & name) const879 std::pair<int32_t, RefPtr<FrameNode>> PageRouterManager::FindPageInStackByRouteName(const std::string& name) const
880 {
881 auto iter = std::find_if(pageRouterStack_.rbegin(), pageRouterStack_.rend(),
882 [name](const WeakPtr<FrameNode>& item) {
883 auto pageNode = item.Upgrade();
884 CHECK_NULL_RETURN(pageNode, false);
885 auto pagePattern = pageNode->GetPattern<PagePattern>();
886 CHECK_NULL_RETURN(pagePattern, false);
887 auto entryPageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
888 CHECK_NULL_RETURN(entryPageInfo, false);
889 return entryPageInfo->GetRouteName() == name;
890 });
891 if (iter == pageRouterStack_.rend()) {
892 return { INVALID_PAGE_INDEX, nullptr };
893 }
894 // Returns to the forward position.
895 return { std::distance(iter, pageRouterStack_.rend()) - 1, iter->Upgrade() };
896 }
897
PushOhmUrl(const RouterPageInfo & target)898 void PageRouterManager::PushOhmUrl(const RouterPageInfo& target)
899 {
900 RouterOptScope scope(this);
901 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE) {
902 LOGW("Router stack size is larger than max size 32.");
903 if (target.errorCallback != nullptr) {
904 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
905 }
906 return;
907 }
908 RouterPageInfo info = target;
909 info.path = info.url + ".js";
910
911 if (target.routerMode == RouterMode::SINGLE) {
912 auto pageInfo = FindPageInStack(info.url);
913 if (pageInfo.second) {
914 // find page in stack, move postion and update params.
915 MovePageToFront(pageInfo.first, pageInfo.second, info, true);
916 return;
917 }
918 }
919
920 LoadPage(GenerateNextPageId(), info);
921 auto container = Container::Current();
922 CHECK_NULL_VOID(container);
923 auto pageUrlChecker = container->GetPageUrlChecker();
924 CHECK_NULL_VOID(pageUrlChecker);
925 auto taskExecutor = container->GetTaskExecutor();
926 CHECK_NULL_VOID(taskExecutor);
927 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
928 TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterPushOhmUrl");
929 }
930
StartPush(const RouterPageInfo & target)931 void PageRouterManager::StartPush(const RouterPageInfo& target)
932 {
933 CHECK_RUN_ON(JS);
934 RouterOptScope scope(this);
935 if (target.url.empty()) {
936 TAG_LOGE(AceLogTag::ACE_ROUTER, "push url is empty");
937 return;
938 }
939 #if !defined(PREVIEW)
940 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
941 auto container = Container::Current();
942 CHECK_NULL_VOID(container);
943 auto pageUrlChecker = container->GetPageUrlChecker();
944 CHECK_NULL_VOID(pageUrlChecker);
945 auto instanceId = container->GetInstanceId();
946 auto taskExecutor = container->GetTaskExecutor();
947 CHECK_NULL_VOID(taskExecutor);
948 auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
949 ContainerScope scope(instanceId);
950 auto pageRouterManager = weak.Upgrade();
951 CHECK_NULL_VOID(pageRouterManager);
952 taskExecutor->PostTask(
953 [pageRouterManager, target]() { pageRouterManager->PushOhmUrl(target); },
954 TaskExecutor::TaskType::JS, "ArkUIPageRouterPushOhmUrl");
955 };
956
957 auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
958 int32_t errorCode, const std::string& errorMsg) {
959 if (!errorCallback) {
960 return;
961 }
962 ContainerScope scope(instanceId);
963 taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
964 TaskExecutor::TaskType::JS, "ArkUIPageRouterPushErrorCallback");
965 };
966
967 pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
968 return;
969 }
970 #endif
971 if (!manifestParser_) {
972 return;
973 }
974 auto context = PipelineContext::GetCurrentContext();
975 CHECK_NULL_VOID(context);
976 if (GetStackSize() >= MAX_ROUTER_STACK_SIZE && !context->GetForceSplitEnable()) {
977 LOGW("Router stack size is larger than max size 32.");
978 if (target.errorCallback != nullptr) {
979 target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
980 }
981 return;
982 }
983 RouterPageInfo info = target;
984 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
985 if (info.path.empty()) {
986 LOGW("[Engine Log] this uri is empty, not support in route push.");
987 if (info.errorCallback != nullptr) {
988 info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
989 }
990 return;
991 }
992
993 CleanPageOverlay();
994
995 if (info.routerMode == RouterMode::SINGLE) {
996 auto pageInfo = FindPageInStack(info.url);
997 if (pageInfo.second) {
998 // find page in stack, move postion and update params.
999 MovePageToFront(pageInfo.first, pageInfo.second, info, true);
1000 return;
1001 }
1002 }
1003
1004 LoadPage(GenerateNextPageId(), info, true, true, true);
1005 }
1006
ReplaceOhmUrl(const RouterPageInfo & target)1007 void PageRouterManager::ReplaceOhmUrl(const RouterPageInfo& target)
1008 {
1009 RouterOptScope scope(this);
1010 RouterPageInfo info = target;
1011 info.path = info.url + ".js";
1012
1013 PopPage("", false, false);
1014
1015 if (info.routerMode == RouterMode::SINGLE) {
1016 auto pageInfo = FindPageInStack(info.url);
1017 if (pageInfo.second) {
1018 // find page in stack, move postion and update params.
1019 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1020 return;
1021 }
1022 }
1023
1024 LoadPage(GenerateNextPageId(), info, false, false);
1025 auto container = Container::Current();
1026 CHECK_NULL_VOID(container);
1027 auto pageUrlChecker = container->GetPageUrlChecker();
1028 CHECK_NULL_VOID(pageUrlChecker);
1029 auto taskExecutor = container->GetTaskExecutor();
1030 CHECK_NULL_VOID(taskExecutor);
1031 taskExecutor->PostTask([pageUrlChecker, url = target.url]() { pageUrlChecker->CheckPreload(url); },
1032 TaskExecutor::TaskType::BACKGROUND, "ArkUIPageRouterReplaceOhmUrl");
1033 }
1034
StartReplace(const RouterPageInfo & target)1035 void PageRouterManager::StartReplace(const RouterPageInfo& target)
1036 {
1037 CHECK_RUN_ON(JS);
1038 CleanPageOverlay();
1039 RouterOptScope scope(this);
1040 if (target.url.empty()) {
1041 return;
1042 }
1043 #if !defined(PREVIEW)
1044 if (target.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1045 auto container = Container::Current();
1046 CHECK_NULL_VOID(container);
1047 auto pageUrlChecker = container->GetPageUrlChecker();
1048 CHECK_NULL_VOID(pageUrlChecker);
1049 auto instanceId = container->GetInstanceId();
1050 auto taskExecutor = container->GetTaskExecutor();
1051 CHECK_NULL_VOID(taskExecutor);
1052 auto callback = [weak = AceType::WeakClaim(this), target, taskExecutor, instanceId]() {
1053 ContainerScope scope(instanceId);
1054 auto pageRouterManager = weak.Upgrade();
1055 CHECK_NULL_VOID(pageRouterManager);
1056 taskExecutor->PostTask([pageRouterManager, target]() { pageRouterManager->ReplaceOhmUrl(target); },
1057 TaskExecutor::TaskType::JS, "ArkUIPageRouterReplaceOhmUrl");
1058 };
1059
1060 auto silentInstallErrorCallBack = [errorCallback = target.errorCallback, taskExecutor, instanceId](
1061 int32_t errorCode, const std::string& errorMsg) {
1062 if (!errorCallback) {
1063 return;
1064 }
1065 ContainerScope scope(instanceId);
1066 taskExecutor->PostTask([errorCallback, errorCode, errorMsg]() { errorCallback(errorMsg, errorCode); },
1067 TaskExecutor::TaskType::JS, "ArkUIPageRouterReplaceErrorCallback");
1068 };
1069
1070 pageUrlChecker->LoadPageUrl(target.url, callback, silentInstallErrorCallBack);
1071 return;
1072 }
1073 #endif
1074 if (!manifestParser_) {
1075 return;
1076 }
1077 RouterPageInfo info = target;
1078 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1079 if (info.path.empty()) {
1080 LOGW("[Engine Log] this uri is empty, not support in route push.");
1081 if (info.errorCallback != nullptr) {
1082 info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
1083 }
1084 return;
1085 }
1086
1087 DealReplacePage(info);
1088 }
1089
StartBack(const RouterPageInfo & target)1090 void PageRouterManager::StartBack(const RouterPageInfo& target)
1091 {
1092 CleanPageOverlay();
1093 if (target.url.empty()) {
1094 size_t pageRouteSize = pageRouterStack_.size();
1095 if (pageRouteSize <= 1) {
1096 if (!restorePageStack_.empty()) {
1097 auto newInfo = RouterPageInfo();
1098 newInfo.params = target.params;
1099 StartRestore(newInfo);
1100 return;
1101 }
1102 LOGI("Router back start ExitToDesktop");
1103 ExitToDesktop();
1104 return;
1105 }
1106 LOGI("Router back start PopPage");
1107 PopPage(target.params, true, true);
1108 return;
1109 }
1110
1111 auto pageInfo = FindPageInStack(target.url, true);
1112 if (pageInfo.second) {
1113 // find page in stack, pop to specified index.
1114 RouterPageInfo info = target;
1115 #if !defined(PREVIEW)
1116 if (info.url.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1117 info.path = info.url + ".js";
1118 PopPageToIndex(pageInfo.first, info.params, true, true);
1119 return;
1120 }
1121 #endif
1122 if (!manifestParser_) {
1123 return;
1124 }
1125
1126 info.path = manifestParser_->GetRouter()->GetPagePath(info.url);
1127 if (info.path.empty()) {
1128 LOGW("[Engine Log] this uri is empty, not support in route push.");
1129 return;
1130 }
1131 PopPageToIndex(pageInfo.first, info.params, true, true);
1132 return;
1133 }
1134 if (!restorePageStack_.empty()) {
1135 StartRestore(target);
1136 }
1137 }
1138
StartBackToIndex(int32_t index,const std::string & params)1139 void PageRouterManager::StartBackToIndex(int32_t index, const std::string& params)
1140 {
1141 CleanPageOverlay();
1142 RouterPageInfo target = GetPageInfoByIndex(index, params);
1143 if (!manifestParser_) {
1144 return;
1145 }
1146 PopPageToIndex(index - 1, params, true, true);
1147 return;
1148 }
1149
BackCheckAlert(const RouterPageInfo & target)1150 void PageRouterManager::BackCheckAlert(const RouterPageInfo& target)
1151 {
1152 RouterOptScope scope(this);
1153 if (pageRouterStack_.empty()) {
1154 TAG_LOGW(AceLogTag::ACE_ROUTER, "Page router stack size is zero, can not back");
1155 return;
1156 }
1157 auto currentPage = GetCurrentPageNode();
1158 CHECK_NULL_VOID(currentPage);
1159 auto pagePattern = currentPage->GetPattern<PagePattern>();
1160 CHECK_NULL_VOID(pagePattern);
1161 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1162 CHECK_NULL_VOID(pageInfo);
1163 if (pageInfo->GetAlertCallback()) {
1164 ngBackTarget_ = target;
1165 auto pipelineContext = PipelineContext::GetCurrentContext();
1166 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1167 CHECK_NULL_VOID(overlayManager);
1168 overlayManager->ShowDialog(
1169 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1170 return;
1171 }
1172 StartBack(target);
1173 }
1174
BackToIndexCheckAlert(int32_t index,const std::string & params)1175 void PageRouterManager::BackToIndexCheckAlert(int32_t index, const std::string& params)
1176 {
1177 RouterOptScope scope(this);
1178 if (pageRouterStack_.empty()) {
1179 return;
1180 }
1181 RouterPageInfo target = GetPageInfoByIndex(index, params);
1182 auto currentPage = GetCurrentPageNode();
1183 CHECK_NULL_VOID(currentPage);
1184 auto pagePattern = currentPage->GetPattern<PagePattern>();
1185 CHECK_NULL_VOID(pagePattern);
1186 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1187 CHECK_NULL_VOID(pageInfo);
1188 if (pageInfo->GetAlertCallback()) {
1189 ngBackTarget_ = target;
1190 auto pipelineContext = PipelineContext::GetCurrentContext();
1191 auto overlayManager = pipelineContext ? pipelineContext->GetOverlayManager() : nullptr;
1192 CHECK_NULL_VOID(overlayManager);
1193 overlayManager->ShowDialog(
1194 pageInfo->GetDialogProperties(), nullptr, AceApplicationInfo::GetInstance().IsRightToLeft());
1195 return;
1196 }
1197 StartBackToIndex(index, params);
1198 }
1199
LoadPage(int32_t pageId,const RouterPageInfo & target,bool needHideLast,bool needTransition,bool)1200 void PageRouterManager::LoadPage(int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition,
1201 bool /*isPush*/)
1202 {
1203 ACE_SCOPED_TRACE_COMMERCIAL("load page: %s(id:%d)", target.url.c_str(), pageId);
1204 CHECK_RUN_ON(JS);
1205 auto pageNode = CreatePage(pageId, target);
1206 if (!pageNode) {
1207 return;
1208 }
1209
1210 pageRouterStack_.emplace_back(pageNode);
1211 if (!OnPageReady(pageNode, needHideLast, needTransition)) {
1212 pageRouterStack_.pop_back();
1213 LOGW("LoadPage OnPageReady Failed");
1214 return;
1215 }
1216 AccessibilityEventType type = AccessibilityEventType::CHANGE;
1217 pageNode->OnAccessibilityEvent(type);
1218 }
1219
CreatePage(int32_t pageId,const RouterPageInfo & target)1220 RefPtr<FrameNode> PageRouterManager::CreatePage(int32_t pageId, const RouterPageInfo& target)
1221 {
1222 ACE_SCOPED_TRACE("PageRouterManager::CreatePage");
1223 CHECK_RUN_ON(JS);
1224 LOGI("Page router manager is loading page[%{public}d]: %{public}s.", pageId, target.url.c_str());
1225 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, target.params);
1226 auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1227 std::unordered_map<std::string, std::string> reportData { { "pageUrl", target.url } };
1228 ResSchedReportScope reportScope("push_page", reportData);
1229 auto pageNode =
1230 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1231 pageNode->SetHostPageId(pageId);
1232 pageRouterStack_.emplace_back(pageNode);
1233
1234 if (target.content && !target.content->empty()) {
1235 loadJsByBuffer_(target.content, target.errorCallback, target.params);
1236 } else {
1237 loadJs_(target.path, target.errorCallback);
1238 }
1239 // record full path info of every pageNode
1240 auto pageInfo = pagePattern->GetPageInfo();
1241 if (!pageInfo) {
1242 pageRouterStack_.pop_back();
1243 return nullptr;
1244 }
1245 auto keyInfo = target.url;
1246 if (keyInfo.empty() && manifestParser_) {
1247 auto router = manifestParser_->GetRouter();
1248 if (router) {
1249 keyInfo = router->GetEntry("");
1250 }
1251 }
1252 #if !defined(PREVIEW)
1253 if (keyInfo.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
1254 // deal with @bundle url
1255 // @bundle format: @bundle:bundleName/moduleName/pagePath/fileName(without file extension)
1256 // @bundle example: @bundle:com.example.applicationHsp/hsp/ets/pages/Index
1257 // only moduleName and lastPagePath/fileName is needed: hsppages/Index
1258 size_t bundleEndPos = keyInfo.find('/');
1259 size_t moduleStartPos = bundleEndPos + 1;
1260 size_t moduleEndPos = keyInfo.find('/', moduleStartPos);
1261 std::string moduleName = keyInfo.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1262 size_t fileNameStartPos = keyInfo.rfind('/');
1263 size_t pageInfoStartPos = keyInfo.rfind('/', fileNameStartPos - 1);
1264 keyInfo = keyInfo.substr(pageInfoStartPos + 1);
1265 keyInfo = moduleName + keyInfo;
1266 }
1267 #endif
1268 SetPageInfoRouteName(entryPageInfo, target.isNamedRouterMode);
1269 auto pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1270 if (pagePath.empty()) {
1271 auto container = Container::Current();
1272 if (!container) {
1273 pageRouterStack_.pop_back();
1274 return nullptr;
1275 }
1276 auto moduleName = container->GetModuleName();
1277 keyInfo = moduleName + keyInfo;
1278 pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo);
1279 }
1280 pageInfo->SetFullPath(pagePath);
1281
1282 #if defined(PREVIEW)
1283 if (!isComponentPreview_()) {
1284 #endif
1285 auto result = loadNamedRouter_(target.url, target.isNamedRouterMode);
1286 if (!result) {
1287 if (!target.isNamedRouterMode) {
1288 result = updateRootComponent_();
1289 } else if (target.errorCallback) {
1290 target.errorCallback("The named route is not exist.", ERROR_CODE_NAMED_ROUTE_ERROR);
1291 }
1292 }
1293
1294 if (!result) {
1295 #if !defined(PREVIEW)
1296 if (!target.isNamedRouterMode && target.url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
1297 ThrowError("Load Page Failed: " + target.url, ERROR_CODE_LOAD_PAGE_ERROR);
1298 }
1299 #endif
1300 pageRouterStack_.pop_back();
1301 return nullptr;
1302 }
1303
1304 if (target.isNamedRouterMode) {
1305 manifestParser_->SetPagePath(target.url);
1306 }
1307
1308 if (target.errorCallback != nullptr) {
1309 target.errorCallback("", ERROR_CODE_NO_ERROR);
1310 }
1311 #if defined(PREVIEW)
1312 }
1313 #endif
1314
1315 pageRouterStack_.pop_back();
1316 return pageNode;
1317 }
1318
LoadCard(int32_t pageId,const RouterPageInfo & target,const std::string & params,int64_t cardId,bool,bool needHideLast,const std::string & entryPoint)1319 UIContentErrorCode PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params,
1320 int64_t cardId, bool /* isRestore */, bool needHideLast, const std::string& entryPoint)
1321 {
1322 CHECK_RUN_ON(JS);
1323 auto entryPageInfo = AceType::MakeRefPtr<EntryPageInfo>(pageId, target.url, target.path, params);
1324 auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo);
1325 auto pageNode =
1326 FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pagePattern);
1327 pageNode->SetHostPageId(pageId);
1328 pageRouterStack_.emplace_back(pageNode);
1329
1330 if (!loadCard_) {
1331 return UIContentErrorCode::NULL_CARD_CALLBACK;
1332 }
1333 auto result = loadCard_(target.url, cardId, entryPoint);
1334 if (!result) {
1335 pageRouterStack_.pop_back();
1336 return UIContentErrorCode::NULL_CARD_RES;
1337 }
1338
1339 if (!OnPageReady(pageNode, needHideLast, false, isCardRouter_, cardId)) {
1340 LOGE("LoadCard OnPageReady Failed");
1341 pageRouterStack_.pop_back();
1342 return UIContentErrorCode::CARD_PAGE_NOT_READY;
1343 }
1344 LOGI("LoadCard Success");
1345 return UIContentErrorCode::NO_ERRORS;
1346 }
1347
MovePageToFront(int32_t index,const RefPtr<FrameNode> & pageNode,const RouterPageInfo & target,bool needHideLast,bool forceShowCurrent,bool needTransition)1348 void PageRouterManager::MovePageToFront(int32_t index, const RefPtr<FrameNode>& pageNode, const RouterPageInfo& target,
1349 bool needHideLast, bool forceShowCurrent, bool needTransition)
1350 {
1351 LOGI("Move page to front to index: %{public}d", index);
1352 if (target.errorCallback != nullptr) {
1353 target.errorCallback("", ERROR_CODE_NO_ERROR);
1354 }
1355
1356 // update param first.
1357 CHECK_NULL_VOID(pageNode);
1358 auto pagePattern = pageNode->GetPattern<PagePattern>();
1359 CHECK_NULL_VOID(pagePattern);
1360 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1361 CHECK_NULL_VOID(pageInfo);
1362
1363 if (index == static_cast<int32_t>(pageRouterStack_.size()) - 1) {
1364 pageInfo->ReplacePageParams(target.params);
1365 if (forceShowCurrent) {
1366 pageNode->GetRenderContext()->ResetPageTransitionEffect();
1367 StageManager::FirePageShow(pageNode, PageTransitionType::NONE);
1368 }
1369 return;
1370 }
1371 CHECK_NULL_VOID(pageNode);
1372 auto container = Container::Current();
1373 CHECK_NULL_VOID(container);
1374 auto pipeline = container->GetPipelineContext();
1375 CHECK_NULL_VOID(pipeline);
1376 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1377 auto stageManager = context ? context->GetStageManager() : nullptr;
1378 CHECK_NULL_VOID(stageManager);
1379
1380 // clean pageNode on index position.
1381 auto iter = pageRouterStack_.begin();
1382 std::advance(iter, index);
1383 auto last = pageRouterStack_.erase(iter);
1384 // push pageNode to top.
1385 pageRouterStack_.emplace_back(pageNode);
1386 std::string tempParam = pageInfo->ReplacePageParams(target.params);
1387 if (!stageManager->MovePageToFront(pageNode, needHideLast, needTransition)) {
1388 // restore position and param.
1389 pageRouterStack_.pop_back();
1390 pageRouterStack_.insert(last, pageNode);
1391 if (!tempParam.empty()) {
1392 pageInfo->ReplacePageParams(tempParam);
1393 }
1394 }
1395
1396 // update index in pageInfo
1397 for (auto iter = last; iter != pageRouterStack_.end(); ++iter, ++index) {
1398 auto pageNode = iter->Upgrade();
1399 if (!pageNode) {
1400 continue;
1401 }
1402 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1403 if (pagePattern) {
1404 pagePattern->GetPageInfo()->SetPageIndex(index + 1);
1405 }
1406 }
1407 }
1408
FlushFrontend()1409 void PageRouterManager::FlushFrontend()
1410 {
1411 auto currentPage = GetCurrentPageNode();
1412 CHECK_NULL_VOID(currentPage);
1413 auto customNode = DynamicCast<CustomNode>(currentPage->GetFirstChild());
1414 CHECK_NULL_VOID(customNode);
1415 customNode->FlushReload();
1416 }
1417
PopPage(const std::string & params,bool needShowNext,bool needTransition)1418 void PageRouterManager::PopPage(const std::string& params, bool needShowNext, bool needTransition)
1419 {
1420 CHECK_RUN_ON(JS);
1421 if (pageRouterStack_.empty()) {
1422 LOGW("Page router stack size is zero, can not pop");
1423 return;
1424 }
1425 if (needShowNext && (pageRouterStack_.size() == 1)) {
1426 LOGW("Page router stack size is only one, can not show next");
1427 return;
1428 }
1429 auto topNode = pageRouterStack_.back();
1430 pageRouterStack_.pop_back();
1431 if (!needShowNext) {
1432 if (!OnPopPage(needShowNext, needTransition)) {
1433 pageRouterStack_.emplace_back(topNode);
1434 }
1435 return;
1436 }
1437
1438 // update param first.
1439 auto nextNode = GetCurrentPageNode();
1440 CHECK_NULL_VOID(nextNode);
1441 auto pagePattern = nextNode->GetPattern<PagePattern>();
1442 CHECK_NULL_VOID(pagePattern);
1443 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1444 CHECK_NULL_VOID(pageInfo);
1445 auto temp = pageInfo->ReplacePageParams(params);
1446
1447 if (OnPopPage(needShowNext, needTransition)) {
1448 return;
1449 }
1450 // restore stack and pageParam.
1451 pageRouterStack_.emplace_back(topNode);
1452 pageInfo->ReplacePageParams(temp);
1453 }
1454
PopPageToIndex(int32_t index,const std::string & params,bool needShowNext,bool needTransition)1455 void PageRouterManager::PopPageToIndex(int32_t index, const std::string& params, bool needShowNext, bool needTransition)
1456 {
1457 TAG_LOGI(AceLogTag::ACE_ROUTER, "pop page to %{public}d", index);
1458 std::list<WeakPtr<FrameNode>> temp;
1459 std::swap(temp, pageRouterStack_);
1460 auto iter = temp.begin();
1461 for (int32_t current = 0; current <= index; ++current) {
1462 pageRouterStack_.emplace_back(*iter);
1463 ++iter;
1464 }
1465
1466 // update param first.
1467 auto nextNode = GetCurrentPageNode();
1468 CHECK_NULL_VOID(nextNode);
1469 auto pagePattern = nextNode->GetPattern<PagePattern>();
1470 CHECK_NULL_VOID(pagePattern);
1471 auto pageInfo = DynamicCast<EntryPageInfo>(pagePattern->GetPageInfo());
1472 CHECK_NULL_VOID(pageInfo);
1473 auto tempParam = pageInfo->ReplacePageParams(params);
1474
1475 if (OnPopPageToIndex(index, needShowNext, needTransition)) {
1476 return;
1477 }
1478 // restore stack and pageParam.
1479 std::swap(temp, pageRouterStack_);
1480 pageInfo->ReplacePageParams(tempParam);
1481 }
1482
OnPageReady(const RefPtr<FrameNode> & pageNode,bool needHideLast,bool needTransition,bool isCardRouter,int64_t cardId)1483 bool PageRouterManager::OnPageReady(const RefPtr<FrameNode>& pageNode, bool needHideLast, bool needTransition,
1484 bool isCardRouter, int64_t cardId)
1485 {
1486 Recorder::NodeDataCache::Get().OnPageReady();
1487 auto container = Container::Current();
1488 CHECK_NULL_RETURN(container, false);
1489 RefPtr<PipelineBase> pipeline;
1490 if (isCardRouter) {
1491 auto weak = container->GetCardPipeline(cardId);
1492 pipeline = weak.Upgrade();
1493 CHECK_NULL_RETURN(pipeline, false);
1494 } else {
1495 pipeline = container->GetPipelineContext();
1496 CHECK_NULL_RETURN(pipeline, false);
1497 }
1498
1499 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1500 auto stageManager = context ? context->GetStageManager() : nullptr;
1501 if (stageManager) {
1502 return stageManager->PushPage(pageNode, needHideLast, needTransition);
1503 }
1504 return false;
1505 }
1506
OnPopPage(bool needShowNext,bool needTransition)1507 bool PageRouterManager::OnPopPage(bool needShowNext, bool needTransition)
1508 {
1509 auto container = Container::Current();
1510 CHECK_NULL_RETURN(container, false);
1511 auto pipeline = container->GetPipelineContext();
1512 CHECK_NULL_RETURN(pipeline, false);
1513 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1514 auto stageManager = context ? context->GetStageManager() : nullptr;
1515 if (stageManager) {
1516 Recorder::NodeDataCache::Get().OnBeforePagePop();
1517 return stageManager->PopPage(needShowNext, needTransition);
1518 }
1519 return false;
1520 }
1521
OnPopPageToIndex(int32_t index,bool needShowNext,bool needTransition)1522 bool PageRouterManager::OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
1523 {
1524 auto container = Container::Current();
1525 CHECK_NULL_RETURN(container, false);
1526 auto pipeline = container->GetPipelineContext();
1527 CHECK_NULL_RETURN(pipeline, false);
1528 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1529 auto stageManager = context ? context->GetStageManager() : nullptr;
1530 if (stageManager) {
1531 Recorder::NodeDataCache::Get().OnBeforePagePop();
1532 return stageManager->PopPageToIndex(index, needShowNext, needTransition);
1533 }
1534 return false;
1535 }
1536
OnCleanPageStack()1537 bool PageRouterManager::OnCleanPageStack()
1538 {
1539 auto container = Container::Current();
1540 CHECK_NULL_RETURN(container, false);
1541 auto pipeline = container->GetPipelineContext();
1542 CHECK_NULL_RETURN(pipeline, false);
1543 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1544 auto stageManager = context ? context->GetStageManager() : nullptr;
1545 if (stageManager) {
1546 return stageManager->CleanPageStack();
1547 }
1548 return false;
1549 }
1550
CleanPageOverlay()1551 void PageRouterManager::CleanPageOverlay()
1552 {
1553 auto container = Container::Current();
1554 CHECK_NULL_VOID(container);
1555 auto pipeline = container->GetPipelineContext();
1556 CHECK_NULL_VOID(pipeline);
1557 auto context = DynamicCast<NG::PipelineContext>(pipeline);
1558 CHECK_NULL_VOID(context);
1559 auto overlayManager = context->GetOverlayManager();
1560 CHECK_NULL_VOID(overlayManager);
1561 auto taskExecutor = context->GetTaskExecutor();
1562 CHECK_NULL_VOID(taskExecutor);
1563 auto sharedManager = context->GetSharedOverlayManager();
1564 if (sharedManager) {
1565 sharedManager->StopSharedTransition();
1566 }
1567
1568 overlayManager->RemoveOverlay(true, true);
1569 }
1570
CheckIndexValid(int32_t index) const1571 bool PageRouterManager::CheckIndexValid(int32_t index) const
1572 {
1573 if (index > static_cast<int32_t>(pageRouterStack_.size()) || index <= 0) {
1574 LOGW("The index is less than or equal to zero or exceeds the maximum length of the page stack");
1575 return false;
1576 }
1577 return true;
1578 }
1579
DealReplacePage(const RouterPageInfo & info)1580 void PageRouterManager::DealReplacePage(const RouterPageInfo& info)
1581 {
1582 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1583 ReplacePageInNewLifecycle(info);
1584 return;
1585 }
1586 PopPage("", false, false);
1587 if (info.routerMode == RouterMode::SINGLE) {
1588 auto pageInfo = FindPageInStack(info.url);
1589 if (pageInfo.second) {
1590 // find page in stack, move position and update params.
1591 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1592 return;
1593 }
1594 }
1595 LoadPage(GenerateNextPageId(), info, false, false);
1596 }
1597
CheckOhmUrlValid(const std::string & ohmUrl)1598 bool PageRouterManager::CheckOhmUrlValid(const std::string& ohmUrl)
1599 {
1600 size_t bundleEndPos = ohmUrl.find('/');
1601 std::string bundleName = ohmUrl.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
1602 size_t moduleStartPos = bundleEndPos + 1;
1603 size_t moduleEndPos = ohmUrl.find('/', moduleStartPos);
1604 std::string moduleName = ohmUrl.substr(moduleStartPos, moduleEndPos - moduleStartPos);
1605 auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
1606 Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
1607 return runtime->IsExecuteModuleInAbcFile(bundleName, moduleName, ohmUrl);
1608 }
1609
ThrowError(const std::string & msg,int32_t code)1610 void PageRouterManager::ThrowError(const std::string& msg, int32_t code)
1611 {
1612 auto runtime = std::static_pointer_cast<Framework::ArkJSRuntime>(
1613 Framework::JsiDeclarativeEngineInstance::GetCurrentRuntime());
1614 runtime->ThrowError(msg, code);
1615 }
1616
GetPageIndex(const WeakPtr<FrameNode> & page)1617 int32_t PageRouterManager::GetPageIndex(const WeakPtr<FrameNode>& page)
1618 {
1619 auto pageNode = page.Upgrade();
1620 CHECK_NULL_RETURN(pageNode, INVALID_PAGE_INDEX);
1621 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1622 CHECK_NULL_RETURN(pagePattern, INVALID_PAGE_INDEX);
1623 auto ret = pagePattern->GetPageInfo()->GetPageIndex();
1624 // frontend index counts from 1, so need -1 for backend use
1625 return ret == INVALID_PAGE_INDEX ? INVALID_PAGE_INDEX : ret - 1;
1626 }
1627
ReplacePageInNewLifecycle(const RouterPageInfo & info)1628 void PageRouterManager::ReplacePageInNewLifecycle(const RouterPageInfo& info)
1629 {
1630 auto pipelineContext = PipelineContext::GetCurrentContext();
1631 CHECK_NULL_VOID(pipelineContext);
1632 #if defined(ENABLE_SPLIT_MODE)
1633 auto stageManager = pipelineContext->GetStageManager();
1634 CHECK_NULL_VOID(stageManager);
1635 #endif
1636 TAG_LOGI(AceLogTag::ACE_ROUTER,
1637 "router replace in new lifecycle(API version > 11), replace mode: %{public}d, url: %{public}s",
1638 static_cast<int32_t>(info.routerMode), info.url.c_str());
1639 auto popNode = GetCurrentPageNode();
1640 int32_t popIndex = static_cast<int32_t>(pageRouterStack_.size()) - 1;
1641 bool findPage = false;
1642 if (info.routerMode == RouterMode::SINGLE) {
1643 auto pageInfo = FindPageInStack(info.url);
1644 // haven't find page by named route's name. Try again with its page path.
1645 if (pageInfo.second == nullptr && info.isNamedRouterMode) {
1646 std::string pagePath = Framework::JsiDeclarativeEngine::GetPagePath(info.url);
1647 pageInfo = FindPageInStack(pagePath);
1648 }
1649 if (pageInfo.first == popIndex) {
1650 // replace top self in SINGLE mode, do nothing.
1651 return;
1652 }
1653 if (pageInfo.second) {
1654 // find page in stack, move position and update params.
1655 #if defined(ENABLE_SPLIT_MODE)
1656 stageManager->SetIsNewPageReplacing(true);
1657 #endif
1658 MovePageToFront(pageInfo.first, pageInfo.second, info, false, true, false);
1659 #if defined(ENABLE_SPLIT_MODE)
1660 stageManager->SetIsNewPageReplacing(false);
1661 #endif
1662 popIndex = popIndex - 1;
1663 findPage = true;
1664 }
1665 }
1666 if (!findPage) {
1667 isNewPageReplacing_ = true;
1668 #if defined(ENABLE_SPLIT_MODE)
1669 stageManager->SetIsNewPageReplacing(true);
1670 #endif
1671 LoadPage(GenerateNextPageId(), info, true, false);
1672 #if defined(ENABLE_SPLIT_MODE)
1673 stageManager->SetIsNewPageReplacing(false);
1674 #endif
1675 isNewPageReplacing_ = false;
1676 }
1677 if (popIndex < 0 || popNode == GetCurrentPageNode() || GetPageIndex(popNode) != popIndex) {
1678 return;
1679 }
1680 auto iter = pageRouterStack_.begin();
1681 std::advance(iter, popIndex);
1682 auto lastIter = pageRouterStack_.erase(iter);
1683 pageRouterStack_.emplace_back(WeakPtr<FrameNode>(AceType::DynamicCast<FrameNode>(popNode)));
1684 popNode->MovePosition(GetLastPageIndex());
1685 for (auto iter = lastIter; iter != pageRouterStack_.end(); ++iter, ++popIndex) {
1686 auto page = iter->Upgrade();
1687 if (!page) {
1688 continue;
1689 }
1690 if (page == popNode) {
1691 // do not change index of page that will be replaced.
1692 continue;
1693 }
1694 auto pagePattern = page->GetPattern<NG::PagePattern>();
1695 pagePattern->GetPageInfo()->SetPageIndex(popIndex + 1);
1696 }
1697 #if defined(ENABLE_SPLIT_MODE)
1698 stageManager->SetIsNewPageReplacing(true);
1699 #endif
1700 PopPage("", false, false);
1701 #if defined(ENABLE_SPLIT_MODE)
1702 stageManager->SetIsNewPageReplacing(false);
1703 #endif
1704 }
1705
SetPageInfoRouteName(const RefPtr<EntryPageInfo> & info,bool isNamedRouterMode)1706 void PageRouterManager::SetPageInfoRouteName(const RefPtr<EntryPageInfo>& info, bool isNamedRouterMode)
1707 {
1708 std::optional<std::string> routeName = std::nullopt;
1709 if (isNamedRouterMode) {
1710 // info->GetPageUrl() represents the name of namedRoute
1711 routeName = info->GetPageUrl();
1712 } else {
1713 auto container = Container::Current();
1714 CHECK_NULL_VOID(container);
1715 // info->GetPageUrl() represents the url of destination page
1716 routeName = Framework::JsiDeclarativeEngine::GetRouteNameByUrl(
1717 info->GetPageUrl(), container->GetBundleName(), container->GetModuleName());
1718 }
1719 info->SetRouteName(routeName);
1720 }
1721 } // namespace OHOS::Ace::NG
1722