【页面路由导航】三步实现页面跳转的完整示例-《精通HarmonyOS NEXT :鸿蒙App开发入门与项目化实战》读者福利

本文为《精通HarmonyOS NEXT :鸿蒙App开发入门与项目化实战》读者福利,对本书感兴趣的同学习可以点击以下链接进行购买,或者参加 班级共同学习,点击链接可进入(华为官方活动)

开始正题

页面路由是App页面跳转必用的技术,在鸿蒙系统中,有多种方案可实现。

而通过Navigation的方式实现页面路由是华为官方当下推荐的方式。Navigation是路由容器组件,一般作为首页的根容器。Navigation组件适用于模块内和跨模块的路由切换,一次开发,多端部署场景。通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果。

Navigation组件主要包含​导航栏(NavBar)和子页(NavDestination),子页通过栈结构管理(存在NavPathStack中)。

通过Navigation组件实现页面之间的跳转,主要分为三步

第一步:导航页面(主页面)如下

@Entry
@Component
struct Index {
  // 创建NavPathStack管理导航栈
  pageStack: NavPathStack = new NavPathStack();
  build() {
    // 在Navigation容器中实现主页面的内容
    Navigation(this.pageStack) {
      Column() {
        // 父视图实现,打开子视图,并传参数
        Button('nav pushPath SecondPage_Nav')
          .onClick(() => {
            this.pageStack.pushPathByName('secondPageNav' , null); // 'secondPageNav'在第三步中定义
          })
      }
    }
    .hideTitleBar(true)
  }
}

第二步:实现子页面

@Builder
export function SecondPageBuilder(name: string, param: Object) {
  SecondPage_Nav()
}

@Entry
@Component
struct SecondPage_Nav {
  pageStack:NavPathStack|null = null;
  build() {
    NavDestination() {
      Button('nav pop Parent')
        .onClick(() => {
          this.pageStack!!.pop()
        })
    }
    .onReady((context: NavDestinationContext) => {
      this.pageStack = context.pathStack;  // 记录上级页面的pageStack
    })
  }
}

第三步:配置路由表

Navigation支持使用系统路由表的方式进行动态路由。各业务模块中需要独立配置route_map.json文件,在触发路由跳转时,需要通过NavPathStack提供的路由方法,传入需要路由的页面配置名称。

// resources/base/profile/route_map.json 文件

{
  "routerMap": [
    {
      "name": "secondPageNav",                                   // 主页面跳转子页面时使用
      "pageSourceFile": "src/main/ets/pages/SecondPage_Nav.ets", // 子页面的源代码文件
      "buildFunction": "SecondPageBuilder",    // 需要与子页面的实现 @Builder描述的export function 名一样。
      "data": {
        "description": "this is pageTwo"
      }
    }
  ]
}

注意:新建的工程,默认没有配置route_map.json文件,需要在在跳转目标模块(子页面)的module.json5配置文件中添加路由表配置

// module.json5 文件

{
  "module" : {
    "routerMap": "$profile:route_map"
  }
}

这三步完成后,通过页面路由导航实现页面跳转的主体代码及配置已经完成,页面之间可以实现自由的跳转及切换了。

<think>首先,用户的问题是:在鸿蒙系统中进行Flutter混合开发时,当页面二次跳转时,Flutter页面不显示,用户想在不使用flutterEntry的情况下寻找替代方案。 用户提供了几个引用,我需要参考这些引用,但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我应该基于用户的问题来回答,而不是直接依赖引用。用户的问题是具体的:解决二次跳转时Flutter页面不显示的问题,且不使用flutterEntry。 关键点: - 问题:页面二次跳转时,Flutter页面不显示。 - 约束:不使用flutterEntry。 - 目标:找到替代方案。 从引用中,我可以提取一些相关信息: - 引用[1]提到使用FlutterEntry实现动态跳转Flutter页面- 引用[2]讨论了在Flutter侧打开鸿蒙原生页面并传递参数。 - 引用[3]提到在鸿蒙应用中添加Flutter页面- 引用[4]说Flutter适配鸿蒙已经稳定。 - 引用[5]描述了在鸿蒙工程中引用Flutter模块源码。 用户的问题焦点是二次跳转页面不显示,不使用flutterEntry。所以,我需要思考为什么会出现这个问题,以及替代方案。 可能的原因: 1. **上下文丢失**:在混合开发中,页面跳转时,Flutter引擎的上下文可能没有被正确传递或维护。 2. **路由管理问题**:Flutter的路由栈和鸿蒙路由栈可能没有正确同步。 3. **Flutter引擎初始化**:Flutter引擎可能没有在需要时初始化或保持活动状态。 不使用flutterEntry的替代方案: - flutterEntry是鸿蒙中用于嵌入Flutter页面的一个组件。如果不使用它,我们需要其他方式来集成Flutter页面- 可能的替代方案: - 使用Flutter的MethodChannel或PlatformChannel来原生鸿蒙代码交互,控制页面跳转-鸿蒙原生页面中,通过某种方式启动和显示Flutter页面- 确保Flutter引擎在整个应用生命周期中保持单例,避免多次初始化。 从引用[2]中,它提到在Flutter发起路由时交给插件处理,并创建了路由页面映射的管理类。这暗示了使用一个中央管理类来处理路由。 解决方案思路: 1. **统一路由管理**:创建一个路由管理器,处理所有页面跳转,无论是原生页面还是Flutter页面。这可以确保跳转时上下文一致。 2. **Flutter引擎保持活跃**:确保Flutter引擎在应用启动时初始化一次,并在整个应用生命周期中保持活动状态。避免在每次跳转时重新初始化引擎。 3. **使用插件机制**:开发一个鸿蒙-Flutter插件,用于在Flutter和鸿蒙之间传递路由命令和参数。 4. **页面栈管理**:在二次跳转时,确保Flutter页面的状态被正确保存和恢复。 具体步骤: -鸿蒙应用中,初始化Flutter引擎一次,例如在应用启动时。 - 当需要跳转到Flutter页面时,通过一个统一的入口点,如一个Activity或Ability,传递路由信息。 - 在Flutter端,使用一个路由框架(如Flutter Navigator)来管理页面堆栈。 - 对于二次跳转,确保在Flutter内部处理跳转,而不是每次都通过原生代码。 在不使用flutterEntry的情况下,我们可以使用鸿蒙的Ability或Page Ability来承载Flutter页面,并通过Intent传递参数。 参考引用[5],它描述了在鸿蒙工程中引用Flutter模块源码,并配置依赖。这可以作为基础。 解决方案: 1. **初始化Flutter引擎**:在鸿蒙应用的入口Ability中,初始化Flutter引擎。确保它是一个单例。 2. **创建Flutter容器**:使用一个自定义的Ability或Page来显示Flutter页面。这个Ability会持有一个FlutterView。 3. **路由跳转**: - 当从原生页面跳转到Flutter页面时,启动这个Flutter容器Ability,并传递路由路径和参数。 - 在Flutter容器中,根据传递的信息初始化Flutter页面- 对于Flutter内部的跳转,使用Flutter Navigator处理。 - 当从Flutter页面跳转回原生页面时,通过MethodChannel通知鸿蒙代码。 4. **处理二次跳转**:确保当从一个Flutter页面跳转到另一个Flutter页面时,在同一个Flutter引擎上下文中进行,而不是创建新的实例。这可以通过在Flutter容器中管理多个Flutter页面实现。 代码示例-鸿蒙端,创建一个FlutterAbility: ```java public class FlutterAbility extends Ability { private FlutterView flutterView; private String initialRoute = "/"; // 默认路由 @Override protected void onStart(Intent intent) { super.onStart(intent); // 从Intent获取路由信息 if (intent != null && intent.hasParameter("route")) { initialRoute = intent.getStringParam("route"); } // 初始化Flutter引擎 FlutterEngine flutterEngine = FlutterEngineCache.getInstance().getEngine(); if (flutterEngine == null) { flutterEngine = new FlutterEngine(this); flutterEngine.getNavigationChannel().setInitialRoute(initialRoute); flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault()); FlutterEngineCache.getInstance().putEngine("default_engine", flutterEngine); } // 创建FlutterView flutterView = new FlutterView(this); flutterView.attachToFlutterEngine(flutterEngine); setUIContent(flutterView); } } ``` - 在原生页面跳转时: ```java Intent intent = new Intent(); intent.setParam("route", "/detail"); // 传递路由路径 startAbility(intent, 0); ``` - 在Flutter端,使用Navigator管理路由: ```dart void main() { runApp(MaterialApp( initialRoute: '/', routes: { '/': (context) => HomePage(), '/detail': (context) => DetailPage(), }, )); } ``` - 对于Flutter内部跳转,直接使用Navigator.push。 确保Flutter引擎缓存:使用FlutterEngineCache来保持引擎活跃。 这样,当二次跳转时,如果是在同一个Flutter容器中,页面应该正常显示,因为引擎是同一个。 如果用户需要从Flutter跳转回原生页面,使用MethodChannel: - 在Flutter中调用MethodChannel发送消息。 -鸿蒙端监听消息,并启动原生Ability。 生成相关问题: 基于用户的问题,生成相关问题: 1. 如何确保Flutter引擎在鸿蒙应用中单例化? 2. Flutter和鸿蒙之间如何高效传递路由参数? 3. 如何处理Flutter页面和原生页面的混合导航栈? 4. 在混合开发中,如何优化性能以避免页面不显示的问题? 5. 是否有其他框架或库可以简化鸿蒙-Flutter混合开发? 回答结构: - 先解释问题原因。 - 然后提供解决方案步骤。 - 最后给出相关问题。</think>### 鸿蒙系统 Flutter 混合开发页面二次跳转问题的解决方案 在鸿蒙系统(HarmonyOS)中进行 Flutter 混合开发时,页面二次跳转时 Flutter 页面不显示的问题,通常源于 **Flutter 引擎上下文丢失**或**路由栈管理不一致**。当不使用 `FlutterEntry`(鸿蒙官方提供的 Flutter 页面嵌入组件)时,需要确保 Flutter 引擎单例化、统一路由管理和参数传递机制。以下是详细解决方案: --- ### 问题原因分析 - **上下文丢失**:二次跳转时,Flutter 引擎可能被重新初始化或销毁,导致页面无法渲染[^2]。 - **路由栈不同步**:鸿蒙原生路由和 Flutter 内部路由(如 Navigator)未正确同步,跳转时状态混乱[^1]。 - **参数传递失败**:页面间传递的参数未被正确处理,Flutter 页面无法根据参数初始化[^2]。 --- ### 替代方案:基于路由管理器和 Flutter 引擎单例化 不使用 `FlutterEntry` 的核心思路是: 1. **初始化 Flutter 引擎为单例**:确保整个应用生命周期中只有一个 Flutter 引擎实例。 2. **创建统一路由管理器**:处理原生鸿蒙页面 Flutter 页面跳转逻辑。 3. **通过 MethodChannel 传递参数**:实现鸿蒙 Flutter 的双向通信。 #### 步骤 1: 初始化 Flutter 引擎单例 在鸿蒙应用的入口 Ability(如 `MainAbility`)中初始化 Flutter 引擎,并缓存为单例。这避免二次跳转时引擎重建。 ```java // MainAbility.java import ohos.aafwk.ability.Ability; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngineCache; public class MainAbility extends Ability { private static final String ENGINE_ID = "default_engine"; private FlutterEngine flutterEngine; @Override protected void onStart(Intent intent) { super.onStart(intent); // 初始化并缓存 Flutter 引擎 flutterEngine = new FlutterEngine(this); flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault()); FlutterEngineCache.getInstance().putEngine(ENGINE_ID, flutterEngine); } } ``` #### 步骤 2: 创建自定义 Flutter 容器 Ability 替代 `FlutterEntry`,创建一个自定义 Ability 作为 Flutter 页面的容器。通过 Intent 传递路由路径和参数。 ```java // FlutterContainerAbility.java import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; import io.flutter.embedding.android.FlutterView; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngineCache; public class FlutterContainerAbility extends Ability { private static final String ENGINE_ID = "default_engine"; @Override protected void onStart(Intent intent) { super.onStart(intent); // 从缓存获取 Flutter 引擎 FlutterEngine flutterEngine = FlutterEngineCache.getInstance().getEngine(ENGINE_ID); // 从 Intent 获取路由参数 String routePath = intent.getStringParam("route"); if (routePath != null) { flutterEngine.getNavigationChannel().setInitialRoute(routePath); } // 创建并附加 FlutterView FlutterView flutterView = new FlutterView(this); flutterView.attachToFlutterEngine(flutterEngine); setUIContent(flutterView); } } ``` #### 步骤 3: 实现统一路由管理器 开发一个路由管理器类,处理所有跳转逻辑: - 原生页面跳转 Flutter:启动 `FlutterContainerAbility` 并传递路由路径。 - Flutter 内部跳转:使用 Flutter Navigator 管理。 - Flutter 跳转原生:通过 MethodChannel 通知鸿蒙。 ```java // RouterManager.java import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; import ohos.aafwk.content.Operation; public class RouterManager { // 跳转到 Flutter 页面 public static void navigateToFlutterPage(Ability context, String routePath) { Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withDeviceId("") .withBundleName(context.getBundleName()) .withAbilityName("com.example.FlutterContainerAbility") .build(); intent.setOperation(operation); intent.setParam("route", routePath); // 传递路由路径 context.startAbility(intent, 0); } // 从 Flutter 跳转回原生页面(通过 MethodChannel 调用) public static void navigateToNativePage(Ability context, String pageName) { // 实现原生页面跳转逻辑 } } ``` #### 步骤 4: 在 Flutter 端集成路由和通信 在 Flutter 项目中,使用 `Navigator` 管理页面栈,并通过 `MethodChannel` 鸿蒙交互。 ```dart // main.dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(MaterialApp( initialRoute: '/', routes: { '/': (context) => HomePage(), '/detail': (context) => DetailPage(), }, )); } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () { // Flutter 内部跳转(二次跳转) Navigator.pushNamed(context, '/detail'); }, child: Text('跳转到详情页'), ), ), ); } } // 初始化 MethodChannel const channel = MethodChannel('com.example/router'); channel.setMethodCallHandler((call) async { if (call.method == 'navigateToNative') { // 处理鸿蒙跳转请求 } }); ``` #### 步骤 5: 配置鸿蒙工程 参考引用[^5],在鸿蒙工程中正确引用 Flutter 模块: 1. 将 Flutter 模块源码复制到鸿蒙工程目录。 2. 在 `build-profile.json5` 中添加模块依赖。 3. 在 `oh-package.json5` 中配置 Flutter 插件。 --- ### 关键优化点 - **引擎单例化**:确保 Flutter 引擎只初始化一次,避免二次跳转时上下文丢失[^2]。 - **参数序列化**:使用 JSON 传递复杂参数(如 `intent.setParam("data", jsonString)`)。 - **生命周期管理**:在 `onStop()` 中暂停引擎,但不要销毁,以节省资源。 - **错误处理**:添加日志监控路由跳转失败(如使用 HiLog 输出调试信息)。 --- ### 相关问题 1. 如何确保 Flutter 引擎在鸿蒙应用退出时正确销毁? 2. 在混合开发中,如何高效传递大型数据(如图片)到 Flutter 页面? 3. Flutter 和鸿蒙原生页面如何共享状态(如用户登录信息)? 4. 如何优化混合应用的启动性能以减少页面加载延迟? 5. 是否有开源库可以简化鸿蒙-Flutter 的路由管理? [^1]: 鸿蒙Flutter实战:25-混合开发详解-5-跳转Flutter页面。在上面的例子中,每次打开的 Flutter 页面是固定的,接下来我们将探讨如何实现动态跳转 Flutter 页面。 [^2]: 鸿蒙-flutter-使用FlutterEntry的路由管理和参数传递。前面我们完成了鸿蒙打开flutter指定页面,并且传递参数,接下来我们看一下在flutter侧打开鸿蒙原生页面,并且传递参数应该如何处理。 [^3]: Flutter鸿蒙化 在鸿蒙应用中添加Flutter页面。我们在实战项目如果公司已经又跨端的方案了 例如Flutter, 我们就可以 FlutterPage 的特性讲Flutter的页面代码通过 FlutterPage 添加到我们现在有的鸿蒙next 项目当中来。 [^4]: flutter作为开源适配框架方案,已经在Android,IOS,Web,Window四大平台进行了适配,一套代码,可以同时展现在多个平台。所以Flutter适配鸿蒙也正式发布了。 [^5]: 鸿蒙harmonyos next flutter混合开发之ohos工程 直接引用 flutter_module 源码。复制 flutter_module 源码 和 flutter相关文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俩毛豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值