欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

Flutter for OpenHarmony 底部Tab扩展实践

作者:maaath

适用对象:希望在开源鸿蒙设备上扩展跨平台应用交互能力的开发者。
参考资料:
OpenHarmony 官网:https://www.openharmony.cn/
OpenHarmony 应用开发文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides
Flutter 官网:https://flutter.dev/
AtomGit:https://atomgit.com

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

一、为什么 Flutter for OpenHarmony 项目需要先补齐宿主页能力

很多人在做 Flutter for OpenHarmony 项目时,会优先把精力投到 Flutter 页面本身,比如列表渲染、网络请求、状态管理或者三方库接入。这当然没问题,但如果只关注 Flutter 业务页,而忽略 OpenHarmony 侧的宿主结构,最终效果往往会比较割裂。页面虽然能显示,应用却不一定“像一个完整产品”。

我这次的实践感受很直接:跨平台应用想在鸿蒙设备上真正立住,不能只有页面内容,还得先把宿主页做扎实。 底部导航、主入口布局、设备验证页、基础服务页,这些看上去像“外围结构”,实际上决定了用户第一次打开应用时的整体认知。

因此,这次我没有继续堆砌零散功能,而是优先做了一件更基础但更有价值的事:扩展开源鸿蒙跨平台应用的核心功能框架。具体来说,就是通过新增底部选项卡、完善首页/服务页/设备页/我的页面,让原本较简单的入口页变成一个可导航、可交互、可验证的主框架。

在我看来,Flutter 与 OpenHarmony 宿主层的关系不是替代,而是协作:

  • Flutter 负责跨平台界面与业务逻辑复用
  • OpenHarmony 宿主负责入口组织、系统承载、设备部署与能力接入

把这两层想明白之后,很多实现路径就顺了。

二、这次扩展的目标是什么

这次实践主要围绕三个目标展开。

1. 新增底部选项卡,扩展交互维度

我把单页面入口改成了四个底部 Tab:

  • 首页
  • 服务
  • 设备
  • 我的

这样做的收益很明显。原先应用只能停留在一个入口上,交互路径单一;而加上底部导航后,用户能够在主框架中快速切换不同能力区域。对 Flutter for OpenHarmony 项目来说,这种结构尤其有意义,因为它天然适合承载:

  • Flutter 页面
  • OpenHarmony 原生页面
  • Flutter + 原生混合页面

也就是说,底部 Tab 不只是 UI 组件,更像是跨平台能力的承载骨架。

2. 完善页面内容,增强服务表达

仅仅有导航还不够,所以我把几个核心页面也一起补齐了:

  • 首页:展示核心概览、服务播报、状态信息
  • 服务页:提供高频服务入口,并加入点击交互
  • 设备页:整理 OpenHarmony 模拟器/设备运行验证信息
  • 我的页:展示用户状态、通知设置与版本信息

这一层改完以后,应用从“示例页”向“可展示的业务壳”迈进了一步。

3. 完成设备侧运行验证

这一点是我很看重的。很多文章会写“理论支持”“可部署”,但没有真正安装运行。为了避免这种空泛描述,这次我在 DevEco Studio 模拟器环境里完成了完整的验证流程:

  • 构建 HAP 成功
  • 安装到模拟器成功
  • Ability 启动成功
  • 查询 bundle 信息成功

所以,这次输出的不是纸面方案,而是经过 OpenHarmony 设备侧验证的结果。

三、实现思路:让宿主页成为 Flutter for OpenHarmony 的稳定容器

本次改动主要集中在 Index.ets。我没有做大范围工程重构,而是尽量保持结构清晰、改动集中。这样的好处是:既便于验证,也方便后续把某个 Tab 替换为 Flutter 页面容器。

下面这段代码定义了主页面的核心状态:

@Entry
@Component
struct Index {
  @State currentTab: number = 0;
  @State selectedService: string = '分诊导览';

  private readonly tabIcons: string[] = ['⌂', '◫', '◎', '☺'];
  private readonly tabLabels: string[] = ['首页', '服务', '设备', '我的'];
  private readonly quickServices: string[] = ['分诊导览', '在线问诊', '检查预约', '报告查询'];
  private readonly newsFeed: string[] = [
    '跨平台核心能力已升级,服务页支持多维快捷入口。',
    '设备页已补充设备状态面板,适合在 OpenHarmony 真机上联调验证。',
    '底部选项卡上线后,关键功能切换路径缩短到一步完成。'
  ];

我很喜欢这类结构明确的写法。currentTab 控制页面切换,selectedService 记录服务页当前选项,逻辑并不复杂,但表达很直接。对后续扩展来说,这种结构很适合作为 Flutter for OpenHarmony 的宿主状态层。

四、底部选项卡是如何实现的

底部导航部分使用的是 ArkUI 组合式实现,保持了较高可读性,也降低了后续维护成本。对于宿主层页面,我不太建议一上来就做过度抽象,因为验证阶段更需要的是稳定和明确。

  @Builder
  BottomTabs() {
    Row() {
      ForEach(this.tabLabels, (item: string, index: number) => {
        this.TabItem(index, this.tabIcons[index], item)
      })
    }
    .width('100%')
    .padding({ left: 10, right: 10, top: 10, bottom: 16 })
    .backgroundColor('#FFFFFF')
    .shadow({ radius: 12, color: '#1A182848', offsetX: 0, offsetY: -2 })
  }

  @Builder
  TabItem(index: number, icon: string, label: string) {
    Column() {
      Text(icon)
        .fontSize(20)
        .fontColor(this.currentTab === index ? '#3158D3' : '#94A3B8')

      Text(label)
        .margin({ top: 6 })
        .fontSize(12)
        .fontWeight(this.currentTab === index ? FontWeight.Bold : FontWeight.Regular)
        .fontColor(this.currentTab === index ? '#182848' : '#94A3B8')
    }
    .width('25%')
    .padding({ top: 6, bottom: 6 })
    .borderRadius(18)
    .backgroundColor(this.currentTab === index ? '#EEF3FF' : '#FFFFFF')
    .onClick(() => {
      this.currentTab = index;
    })
  }

这段实现的优点比较明确:

  • 结构清晰,读起来没有障碍
  • 交互反馈直接,激活态和未激活态区分明显
  • 后续如果要将某个 Tab 对接 Flutter 渲染页,迁移成本较低

从实践效果来说,我认为底部 Tab 是这次改动里最值得保留的部分之一,因为它让整个应用的主框架一下子“立起来了”。

五、服务页为什么值得单独强化

服务页不是简单放几个文案,而是加入了可点击的高频服务入口。用户点击后,当前选中项会即时变化,这样可以更真实地模拟跨平台业务场景,比如在线问诊、预约检查、报告查询等。

  @Builder
  ServiceTab() {
    Scroll() {
      Column({ space: 14 }) {
        Text('高频服务')
          .width('100%')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#182848')

        ForEach(this.quickServices, (item: string) => {
          Row() {
            Column() {
              Text(item)
                .fontSize(16)
                .fontWeight(FontWeight.Medium)
                .fontColor('#182848')
              Text('一键进入对应流程,减少跨页面跳转。')
                .margin({ top: 6 })
                .fontSize(12)
                .fontColor('#6B7280')
            }
            .alignItems(HorizontalAlign.Start)

            Blank()

            Button(this.selectedService === item ? '已选中' : '进入')
              .height(34)
              .fontSize(13)
              .backgroundColor(this.selectedService === item ? '#182848' : '#4A7BFF')
              .fontColor('#FFFFFF')
              .borderRadius(17)
              .onClick(() => {
                this.selectedService = item;
              })
          }

这一页也很适合作为后续接入 OpenHarmony 兼容三方库的承载区域。按照题目建议,后续可以优先考虑:

  • 网络请求类库:拉取服务列表、公告、活动信息
  • 本地存储类库:保存最近使用服务、用户偏好
  • WebView 类能力:承载活动页、服务协议页
  • 图表组件:展示使用趋势、服务数据统计

在跨平台应用里,宿主页先把容器搭好,后面再挂载三方能力,会比一开始就把依赖堆进去稳很多。我个人更推荐这种节奏。

六、OpenHarmony 设备运行验证:不是“理论可行”,而是已经跑起来了

这次验证是在 DevEco Studio 模拟器中完成的,设备目标识别结果为:

127.0.0.1:5555

之后完成了以下流程:

  1. 构建 HAP
  2. 安装到模拟器
  3. 启动 EntryAbility
  4. 查询应用 bundle 信息确认安装成功

最终生成的安装包路径为:

C:\Users\ThinkPad\DevEcoStudioProjects\MyApplication\entry\build\default\outputs\default\entry-default-unsigned.hap

需要说明的是,当前工程没有配置 signingConfigs,所以生成的是 unsigned.hap。不过在本次调试环境中,应用依旧可以顺利安装并启动。从实际效果看,这已经足以作为“设备运行验证”的依据。

七、运行截图验证

为了满足“代码在鸿蒙设备上成功运行并附截图验证”的要求,我把目录中的截图也补进文章里。你后续如果重新截图,只需要替换同名文件即可。

图 1:应用在 OpenHarmony 模拟器上的运行效果

在这里插入图片描述

从这张图可以重点观察:

  • 应用主界面已经成功进入运行态
  • 底部导航框架已显示
  • 页面区域可正常承载主内容

图 2:页面交互与多区域展示效果

在这里插入图片描述

在这里插入图片描述

这两张图更适合用来说明:

  • 底部 Tab 切换后的页面呈现是正常的
  • 宿主页结构已经具备继续承载 Flutter 页面或三方能力的基础
  • 整体 UI 没有出现明显布局错误或重大逻辑异常

如果你后面还要投稿,我建议再补一张“服务页按钮点击后显示已选中”的截图,这样文章的说服力会更强。

八、如何理解它与 Flutter for OpenHarmony 的关系

这里我想单独解释一下,避免读者把文章理解成“只是一个 ArkUI 页面改造”。

本文展示的代码确实主要落在 OpenHarmony 宿主层,但它依然是围绕 Flutter for OpenHarmony 跨平台落地来展开的。因为实际项目里,Flutter 页面要想稳定部署到鸿蒙设备,宿主层必须先解决几个关键问题:

  • 入口页怎么组织
  • 页面框架怎么承载
  • 系统 Ability 怎么接入
  • 设备部署如何验证
  • 三方兼容能力挂载到哪里

很多时候,Flutter 负责的是:

  • 跨平台 UI 复用
  • 业务逻辑沉淀
  • 组件体系统一

而 OpenHarmony 宿主负责的是:

  • 容器组织
  • 生命周期管理
  • 系统能力接入
  • 设备安装与启动验证

我自己的理解是,Flutter for OpenHarmony 真正的难点,从来不只是“页面能不能渲染”,而是“工程能不能在鸿蒙设备上稳定落地”。 这也是为什么我会优先补齐底部 Tab、页面容器和设备验证链路。

九、后续怎么进一步增强这套方案

如果想让这篇文章对应的项目更符合“跨平台 + 三方库”的方向,我建议继续往下做三件事。

1. 在服务页接入已兼容 OpenHarmony 的三方库

优先可以考虑:

  • 网络请求
  • 本地存储
  • WebView
  • 图表展示

这样不仅符合题目“推荐使用兼容三方库”的要求,也能让页面从静态演示变成真正的业务入口。

2. 用 Flutter 页面替换一个 Tab

例如把“服务”页替换成 Flutter 渲染页,而“首页”和“设备”页继续保留原生承载。这样的混合结构,反而更接近真实项目,而不是纯展示工程。

3. 将项目托管到 AtomGit

如果后续要公开代码,建议使用:

https://atomgit.com

这样既符合规范,也便于后续沉淀成完整的开源实践案例。

十、结语

回看这次实践,我最强烈的感受是:跨平台应用要在开源鸿蒙设备上真正站稳,必须先把宿主页做好。 Flutter 页面的价值当然很高,但如果缺少稳定的宿主结构、清晰的导航组织和可验证的部署链路,最终工程很难给人信服力

通过这次改造,我完成了以下内容:

  • 扩展了应用主框架
  • 新增了底部 Tab 导航
  • 完善了多页面内容
  • 增加了服务页交互
  • 完成了 OpenHarmony 模拟器运行验证

从结果来看,这已经不是简单的“Hello World” 页面演示,而是一个具备导航、交互和设备验证能力的 Flutter for OpenHarmony 宿主页模板。对我来说,这种模板价值很高,因为它为后续接入 Flutter 页面和 OpenHarmony 兼容三方库打下了稳定基础。

感谢各位阅读!


Schema.org 结构化数据

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Flutter for OpenHarmony 底部Tab扩展实践",
  "author": {
    "@type": "Person",
    "name": "maaath"
  },
  "publisher": {
    "@type": "Organization",
    "name": "maaath"
  },
  "description": "本文围绕 Flutter for OpenHarmony 跨平台技术,介绍如何在 OpenHarmony 宿主层新增底部选项卡、完善页面结构、增强服务交互,并完成鸿蒙设备运行验证。",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://openharmonycrossplatform.csdn.net"
  },
  "keywords": [
    "OpenHarmony",
    "Flutter for OpenHarmony",
    "开源鸿蒙",
    "跨平台",
    "底部选项卡",
    "ArkUI",
    "设备运行验证"
  ],
  "articleBody": "欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net。本文围绕 Flutter for OpenHarmony 项目在 OpenHarmony 宿主层的能力扩展展开,重点包括底部选项卡设计、多页面完善、服务交互增强,以及在鸿蒙设备上的构建、安装、启动与验证过程。"
}
</script>
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐