HarmonyOS 引导页项目实战:一步步完成从零到可运行

本文面向初学者与一线开发,带你从一个空的 Entry 工程开始,按步骤实现“首次启动进入引导页、完成后进入主页面、支持主题持久化与用户数据存储”的完整功能。跟着做即可复现本项目功能。


你将实现的效果

  • 首次启动:自动进入三步引导页(欢迎 → 数据收集 → 完成)。
  • 完成引导:记录状态,后续启动直接进入主页面。
  • 数据保存:表单信息使用 Preferences 持久化。
  • 主题支持:深色/浅色模式全局生效并持久化。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


环境准备

  • DevEco Studio(建议最新稳定版)
  • HarmonyOS SDK(与项目模板匹配版本)
  • 能运行手机/模拟器

步骤 0:创建或打开工程

  • 使用 DevEco Studio 创建默认 Entry 工程,包结构保持默认。
  • 下文以模块名 entry、主页面 pages/Index 为例。

步骤 1:建立目录结构

entry/src/main/ets 下创建目录:

models/
utils/
pages/
└─ onboarding/

步骤 2:注册页面路由(必做)

编辑文件:entry/src/main/resources/base/profile/main_pages.json

确保包含以下页面路径(缺失将导致“can’t find this page … path”错误):

{
  "src": [
    "pages/Index",
    "pages/onboarding/WelcomeGuidePage",
    "pages/onboarding/DataCollectionPage",
    "pages/onboarding/CompletionPage"
  ]
}

步骤 3:应用入口 EntryAbility

文件:entry/src/main/ets/entryability/EntryAbility.ets

要点:

  • onCreate 中初始化 AppStorage 的全局主题键 app_is_dark_mode
  • onWindowStageCreateloadContent('pages/Index')

代码示例(片段):

AppStorage.setOrCreate('app_is_dark_mode', false);
windowStage.loadContent('pages/Index');

步骤 4:创建主题模型 ThemeModel

文件:entry/src/main/ets/models/ThemeModel.ets

职责:

  • 从 Preferences 读取/保存 is_dark_mode
  • 同步到 AppStorage('app_is_dark_mode'),供全局订阅。

完整代码:

/**
 * 主题模型 - 管理应用主题
 */
import { preferences } from '@kit.ArkData'
import { common } from '@kit.AbilityKit'

export class ThemeModel {
  private isDarkMode: boolean = false
  private preferencesInstance: preferences.Preferences | null = null

  async loadThemeSettings(): Promise<void> {
    try {
      const context = getContext() as common.UIAbilityContext
      this.preferencesInstance = await preferences.getPreferences(context, 'theme_preferences')
      const saved = await this.preferencesInstance.get('is_dark_mode', false) as boolean
      this.isDarkMode = saved
      AppStorage.setOrCreate('app_is_dark_mode', this.isDarkMode)
    } catch (error) {
      console.error('ThemeModel', '加载主题设置失败:', error)
    }
  }

  async toggleTheme(): Promise<void> {
    try {
      this.isDarkMode = !this.isDarkMode
      AppStorage.setOrCreate('app_is_dark_mode', this.isDarkMode)
      if (this.preferencesInstance) {
        await this.preferencesInstance.put('is_dark_mode', this.isDarkMode)
        await this.preferencesInstance.flush()
      }
    } catch (error) {
      console.error('ThemeModel', '切换主题失败:', error)
    }
  }

  getIsDarkMode(): boolean {
    return this.isDarkMode
  }
}

步骤 5:创建引导状态管理 OnboardingManager

文件:entry/src/main/ets/utils/OnboardingManager.ets

职责:

  • 使用 Preferences 记录是否完成引导。
  • 封装单例,提供 initialize/hasShown/mark/reset

完整代码:

/** 引导页管理器 */
import { preferences } from '@kit.ArkData'
import { common } from '@kit.AbilityKit'

const PREFERENCES_NAME = 'onboarding_preferences'
const KEY_HAS_SHOWN_ONBOARDING = 'has_shown_onboarding'

export class OnboardingManager {
  private static instance: OnboardingManager | null = null
  private preferencesInstance: preferences.Preferences | null = null
  private isInitialized: boolean = false
  private constructor() {}
  static getInstance(): OnboardingManager {
    if (!OnboardingManager.instance) OnboardingManager.instance = new OnboardingManager()
    return OnboardingManager.instance
  }
  async initialize(context: common.UIAbilityContext): Promise<void> {
    if (this.isInitialized) return
    this.preferencesInstance = await preferences.getPreferences(context, PREFERENCES_NAME)
    this.isInitialized = true
    console.info('OnboardingManager', '初始化成功')
  }
  async hasShownOnboarding(): Promise<boolean> {
    if (!this.preferencesInstance) return false
    try {
      const hasShown = await this.preferencesInstance.get(KEY_HAS_SHOWN_ONBOARDING, false) as boolean
      console.info('OnboardingManager', `引导页显示状态: ${hasShown}`)
      return hasShown
    } catch (e) {
      console.error('OnboardingManager', '读取引导页状态失败:', e)
      return false
    }
  }
  async markOnboardingAsShown(): Promise<void> {
    if (!this.preferencesInstance) return
    await this.preferencesInstance.put(KEY_HAS_SHOWN_ONBOARDING, true)
    await this.preferencesInstance.flush()
  }
  async resetOnboardingStatus(): Promise<void> {
    if (!this.preferencesInstance) return
    await this.preferencesInstance.put(KEY_HAS_SHOWN_ONBOARDING, false)
    await this.preferencesInstance.flush()
  }
}

步骤 6:创建引导页 - WelcomeGuidePage

文件:entry/src/main/ets/pages/onboarding/WelcomeGuidePage.ets

要点:

  • @Entry @Component 页面。
  • 顶部安全区、主题适配、进度指示、跳过与下一步。

关键片段:

@Entry
@Component
struct WelcomeGuidePage {
  @State themeModel: ThemeModel = new ThemeModel()
  @StorageProp('app_is_dark_mode') isDarkMode: boolean = false
  async aboutToAppear() { await this.themeModel.loadThemeSettings() }
  build() {
    // ... UI,下一步:router.pushUrl({ url: 'pages/onboarding/DataCollectionPage' })
  }
}

完整实现可参考本仓库同名文件。


步骤 7:创建引导页 - DataCollectionPage

文件:entry/src/main/ets/pages/onboarding/DataCollectionPage.ets

要点:

  • 表单输入 + 选项选择。
  • 校验后保存到 Preferences。
  • 下一步跳转到完成页。

关键片段:

private async saveData() {
  const context = getContext(this) as common.UIAbilityContext
  const prefs = await preferences.getPreferences(context, 'onboarding_data')
  await prefs.put('user_name', this.userName)
  await prefs.put('selected_option', this.selectedOption)
  await prefs.flush()
}

步骤 8:创建引导页 - CompletionPage

文件:entry/src/main/ets/pages/onboarding/CompletionPage.ets

要点:

  • 点击“开始使用”时,调用 OnboardingManager.markOnboardingAsShown()
  • 跳转回 pages/Index

关键片段:

const manager = OnboardingManager.getInstance()
await manager.initialize(getContext(this) as common.UIAbilityContext)
await manager.markOnboardingAsShown()
router.replaceUrl({ url: 'pages/Index' })

步骤 9:修改首页 Index.ets(引导决策)

文件:entry/src/main/ets/pages/Index.ets

要点:

  • aboutToAppear 初始化主题并检查引导状态。
  • 未完成引导 → 延时 replaceUrl 到欢迎页。
  • 外层容器必须设置背景色,避免白屏。

关键片段:

async aboutToAppear() {
  await this.themeModel.loadThemeSettings()
  await this.checkOnboardingStatus()
}

setTimeout(() => {
  router.replaceUrl({ url: 'pages/onboarding/WelcomeGuidePage' })
}, 100)

Column() { /* ... */ }
.width('100%').height('100%')
.backgroundColor(this.isDarkMode ? '#121212' : '#F5F5F5')

步骤 10:编译与运行

# DevEco Studio
Build > Build App(s)
Run  或  Shift + F10

步骤 11:测试用例

  • 首次启动:应自动进入引导页第 1 步。
  • 填表完成 → 进入完成页 → 点击“开始使用” → 返回首页。
  • 再次启动:应直接进入首页,不再显示引导页。
  • 重置状态(可选):
hdc shell pm uninstall <你的包名>
# 或在代码中调用 OnboardingManager.resetOnboardingStatus()

常见问题与排查

  1. 报错 “can’t find this page … path”
  • 确认 main_pages.json 已注册所有引导页路径。
  1. 启动白屏
  • 确认首页最外层容器设置了 .backgroundColor(...)
  1. 主题不切换
  • 确认 EntryAbility.onCreate 已初始化 AppStorage('app_is_dark_mode')
  1. 数据未保存
  • 确认 await prefs.flush() 已调用。

目录与参考实现

本项目完整实现已包含在以下文件中,可直接对照复制:

  • entry/src/main/ets/models/ThemeModel.ets
  • entry/src/main/ets/utils/OnboardingManager.ets
  • entry/src/main/ets/pages/Index.ets
  • entry/src/main/ets/pages/onboarding/WelcomeGuidePage.ets
  • entry/src/main/ets/pages/onboarding/DataCollectionPage.ets
  • entry/src/main/ets/pages/onboarding/CompletionPage.ets
  • entry/src/main/resources/base/profile/main_pages.json
  • entry/src/main/ets/entryability/EntryAbility.ets

进阶:自定义与扩展

  • 新增引导步骤:在 pages/onboarding 下创建页面,并在 main_pages.json 注册,更新前一页的 router.pushUrl
  • 自定义主题:在各页面使用 @StorageProp('app_is_dark_mode') 动态切换颜色。
  • 表单扩展:在 DataCollectionPage 新增输入字段并在 saveData() 中持久化。

结束语

到此,你已经完成了一个可用的 HarmonyOS 引导页系统。从架构、状态管理到页面编排、主题与存储,都具备了可扩展的实践基础。根据业务继续迭代即可上线使用。

源代码
https://gitcode.com/daleishen/onboarding
班级链接
https://developer.huawei.com/consumer/cn/training/classDetail/fd34ff9286174e848d34cde7f512ce22?type=1%3Fha_source%3Dhmosclass&ha_sourceId=89000248

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐