《鸿蒙原生应用开发实战》第一篇:项目框架搭建与路由体系

前言

从零开始构建一个鸿蒙原生应用,第一步就是搭好脚手架。本文将详细讲解如何基于 HarmonyOS Stage 模型,从创建项目到完成路由体系的完整搭建。我们以「光遇·心境」App 为例,这是一个沉浸式光感场景探索应用。

本文将涵盖:

  • Stage 模型与 FA 模型的区别
  • 项目目录结构与配置文件
  • Ability 的注册与生命周期
  • 沉浸式窗口配置(状态栏/导航栏透明)
  • 页面路由注册与跳转体系

一、Stage 模型 vs FA 模型

HarmonyOS 从 API 9 开始推荐使用 Stage 模型,相比旧的 FA 模型,Stage 模型有以下优势:

对比维度 Stage 模型 FA 模型
组件化 一个应用包含多个 Module 以 Ability 为核心
生命周期 UIAbility + ExtensionAbility 明确分工 生命周期耦合较重
窗口管理 WindowStage 统一管理 每个 Ability 各自管理
后台任务 ExtensionAbility 专职后台 与前台 Ability 混在一起

本项目配置 build-profile.json5 中指定了 stage 模式:

{
  "apiType": "stageMode",
  "buildOption": {
    "resOptions": {
      "copyCodeResource": {
        "enable": false
      }
    }
  }
}

二、项目目录结构解析

一个标准的 Stage 模型项目结构如下:

MyApplication/
├── AppScope/                    # 全局应用配置
│   ├── app.json5                # 应用级配置(bundleName、版本号等)
│   └── resources/
│       ├── base/element/        # 全局资源(string.json)
│       └── media/               # 应用图标
├── entry/                       # 主模块
│   ├── src/main/
│   │   ├── ets/
│   │   │   ├── entryability/    # Ability 入口
│   │   │   ├── entrybackupability/ # 备份扩展能力
│   │   │   ├── model/           # 数据模型层
│   │   │   └── pages/           # 页面层
│   │   ├── module.json5         # 模块配置
│   │   └── resources/           # 模块资源
│   └── build-profile.json5      # 模块构建配置
├── build-profile.json5          # 项目级构建配置
└── hvigor/                      # 构建工具配置

AppScope/app.json5 —— 应用的"身份证"

{
  "app": {
    "bundleName": "com.example.myapplication",  // 应用唯一标识
    "vendor": "example",
    "versionCode": 1000000,                      // 版本号(整数)
    "versionName": "1.0.0",                      // 展示给用户的版本
    "icon": "$media:layered_image",              // 应用图标
    "label": "$string:app_name"                  // 应用名称
  }
}

⚠️ 注意事项app_name 只需在 AppScope 中定义一次,不可在 entry 模块的 string.json 中重复定义,否则编译会报资源重复错误。


三、Ability 注册与生命周期

EntryAbility —— 应用的"大门"

// entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  // 1. Ability 创建时调用 —— 适合做全局初始化
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 设置颜色模式(跟随系统)
    this.context.getApplicationContext().setColorMode(
      ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
    );
  }

  // 2. WindowStage 创建 —— 这是最关键的生命周期方法
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 这里配置沉浸式窗口
    // ...
    // 加载首页
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', '加载失败: %{public}s', JSON.stringify(err));
      }
    });
  }

  // 3. 前后台切换
  onForeground(): void { /* 应用进入前台 */ }
  onBackground(): void { /* 应用进入后台 */ }

  // 4. 销毁
  onDestroy(): void { /* 释放资源 */ }
}

module.json5 —— Ability 的注册地

{
  "module": {
    "name": "entry",
    "type": "entry",         // entry=主模块, feature=特性模块
    "mainElement": "EntryAbility",  // 入口 Ability
    "deviceTypes": ["phone"],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "exported": true,     // 是否暴露给外部应用调用
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["ohos.want.action.home"]  // 桌面图标启动
          }
        ]
      }
    ],
    // 扩展 Ability —— 这里我们注册了备份能力
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",    // 备份恢复类型
        "exported": false
      }
    ]
  }
}

四、沉浸式窗口 —— 打造全屏无边框体验

作为光感场景应用,沉浸式体验是核心。我们需要让内容延伸到状态栏和导航栏区域。

// EntryAbility.ets —— onWindowStageCreate 中的关键配置
onWindowStageCreate(windowStage: window.WindowStage): void {
  windowStage.getMainWindow((err, wnd) => {
    // 1. 启用全屏布局(状态栏和导航栏区域也可绘制内容)
    wnd.setWindowLayoutFullScreen(true, (err1) => {
      // 2. 设置状态栏和导航栏透明
      wnd.setWindowSystemBarProperties({
        statusBarColor: '#00000000',        // 完全透明
        navigationBarColor: '#00000000',    // 完全透明
        isStatusBarLightIcon: true,         // 白色图标(适配深色背景)
        isNavigationBarLightIcon: true      // 白色图标
      });
      // 3. 窗口背景透明(避免白块闪烁)
      wnd.setWindowBackgroundColor('#00000000');
    });
  });
}

实现效果:

  • 状态栏不再是黑条或白条,而是完全透明
  • 页面的渐变背景从屏幕顶部开始渲染
  • 底部导航栏同样透明,页面内容铺满全屏

页面中需要预留状态栏高度的占位:

build() {
  Column() {
    // 状态栏占位(5%高度的空行,让内容不被状态栏遮挡)
    Row().height('5%').width('100%')
    
    // 实际内容...
    Scroll() { /* ... */ }
  }
}

五、页面路由注册体系

路由表配置

main_pages.json 中注册所有页面路由:

{
  "src": [
    "pages/Index",        // 首页
    "pages/ScenePage",    // 场景探索列表页
    "pages/DetailPage",   // 场景详情页
    "pages/FavPage",      // 收藏页
    "pages/ProfilePage"   // 个人中心页
  ]
}

路由规范

API 23 下,路由的导入和使用有严格规范:

// ✅ 正确的导入方式
import router from '@ohos.router';

// ❌ 错误方式(API 23 不导出此路径)
// import router from '@kit.AbilityKit';

// 页面跳转(携带参数)
router.pushUrl({
  url: 'pages/DetailPage',
  params: { sceneId: 1 }
});

// 页面返回
router.back();

// 接收参数
const params = router.getParams() as Record<string, Object>;
const id = params['sceneId'] as number;

路由体系总览

Index(首页)
 ├── push → ScenePage(场景列表,可携带 category 参数)
 │     └── push → DetailPage(场景详情,携带 sceneId)
 ├── push → DetailPage(每日推荐直接进入)
 ├── push → FavPage(收藏页)
 └── push → ProfilePage(个人中心)

这种星型路由结构非常清晰:所有子页面都可以通过 router.back() 返回首页,用户体验一致。


六、构建配置说明

API 版本配置(build-profile.json5)

{
  "products": [
    {
      "name": "default",
      "targetSdkVersion": "6.1.1(24)",    // 目标 SDK
      "compatibleSdkVersion": "6.1.0(23)", // 兼容的最低 SDK
      "runtimeOS": "HarmonyOS",
      "buildOption": {
        "strictMode": {
          "caseSensitiveCheck": true,
          "useNormalizedOHMUrl": true   // ArkTS 严格模式
        }
      }
    }
  ]
}

构建命令

hvigorw --mode module -p module=entry@default -p product=default \
        -p requiredDeviceType=phone assembleHap \
        --analyze=normal --parallel --incremental --daemon

七、常见踩坑记录

坑1:app_name 重复定义

现象:编译报错 “duplicate resource”
原因:同时在 AppScope 和 entry 模块中定义了 app_name
解决app_name 只在 AppScope/resources/base/element/string.json 中定义

坑2:router 导入路径错误

现象:运行时崩溃 “Cannot find module”
原因:API 23 不支持 @kit.AbilityKit 导出的 router
解决:统一使用 import router from '@ohos.router'

坑3:沉浸式窗口出现白底闪烁

现象:启动时背景短暂变白
原因startWindowBackground 未设置为深色
解决:在 module.json5 中将 startWindowBackground 设为 $color:start_window_background(在我们项目中是 #1a1a2e


在这里插入图片描述

总结

本篇我们完成了:

  1. ✅ 理解 Stage 模型的核心概念
  2. ✅ 项目目录结构与配置文件解析
  3. ✅ Ability 生命周期与注册
  4. ✅ 沉浸式窗口配置实战
  5. ✅ 页面路由注册与跳转体系
  6. ✅ 构建配置与常见踩坑记录

项目的路由体系是整个应用的骨架,下一篇我们将深入 ArkTS 数据模型设计,看看如何优雅地管理应用的状态和数据流。

下一篇预告:ArkTS 数据模型与状态管理 —— @State 装饰器、AppStorage 全局存储、数据流设计模式

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐