HarmonyOS NEXT AI 智能生活助手:创建企业级 AI 工程与目录结构

前言

在上一篇 [项目规划与架构设计] 中,我们详细介绍了 HarmonyAI 的整体架构和 30 篇博客规划。本文是系列的第 02 篇,将带领大家从零开始创建一个企业级的 HarmonyOS NEXT AI 工程。

企业级工程 不是简单的新建项目,而是按照生产级标准搭建项目骨架,包括目录结构、模块划分、依赖管理、代码规范等。好的工程结构是后续 28 篇博客的基础。

本文将涵盖:

  1. 两阶段创建流程:先创建基础工程,再搭建企业级目录结构
  2. 完整目录树:18+ 个模块目录设计
  3. 核心配置:build-profile.json5、oh-package.json5、hvigorfile.ts
  4. 首个页面:验证项目可编译运行
  5. Git 初始化:版本控制与 Tag 管理

在这里插入图片描述

图1:HarmonyAI 企业级目录结构树

一、创建基础工程

1.1 环境准备

在开始之前,请确保已安装以下开发环境:

工具版本要求说明
DevEco Studio5.0+HarmonyOS NEXT 官方 IDE
HarmonyOS SDK5.0.0+API 12+
Node.js18+用于 hvigor 构建
Git2.30+版本控制

1.2 使用 DevEco Studio 创建基础工程

打开 DevEco Studio,按以下步骤操作:

  1. 点击 Create Project
  2. 选择 Empty Ability 模板
  3. 配置项目信息:
配置项值说明
Project NameHarmonyAI项目名称
Bundle Namecom.harmonyai.app应用包名
Save Location自定义路径建议不含中文字符
Compatible API12+API 版本
ModelStage应用模型
LanguageArkTS开发语言
Device TypePhone目标设备

1.3 创建完成后生成的目录

DevEco Studio 默认生成的项目结构如下:

HarmonyAI/
├── AppScope/
│   ├── app.json5             # 应用配置
│   └── resources/            # 应用级资源
├── entry/
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── entryability/
│   │   │   │   │   └── EntryAbility.ts
│   │   │   │   └── pages/
│   │   │   │       └── Index.ets
│   │   │   └── resources/
│   │   └── module.json5
│   ├── build-profile.json5   # HAP 构建配置
│   └── oh-package.json5      # 依赖配置
├── hvigor/
│   └── hvigor-config.json5
├── hvigorfile.ts             # Hvigor 构建入口
├── oh-package.json5          # 顶层依赖配置
├── build-profile.json5       # 顶层构建配置
└── local.properties          # 本地 SDK 路径

二、搭建企业级目录结构

2.1 设计思路

企业级目录结构遵循以下原则:

  1. 按功能模块划分:每个目录有明确的职责
  2. 高内聚低耦合:模块间通过接口通信
  3. 可扩展性:新增功能不需要改动现有目录
  4. 领域驱动:按业务领域组织代码

根据 Project-Design.md 的规划,我们需要在 entry/src/main/ets/ 下新增以下目录:

2.2 完整目录树

ets/
├── entryability/
│   └── EntryAbility.ts       # Ability 入口
├── pages/                    # 页面目录(12-15 个页面)
│   ├── SplashPage.ets        # 启动页
│   ├── HomePage.ets          # 首页
│   ├── ChatPage.ets          # AI 聊天页
│   ├── OCRPage.ets           # OCR 识别页
│   ├── TranslatePage.ets     # 翻译页
│   ├── FlowerPage.ets        # 每日花语页
│   ├── SummaryPage.ets       # 文章总结页
│   ├── CodePage.ets          # 代码解释页
│   ├── TodoPage.ets          # 待办生成页
│   ├── SchedulePage.ets      # 日程规划页
│   ├── SettingPage.ets       # 设置页
│   └── AboutPage.ets         # 关于页
├── components/               # 公共组件
│   ├── ChatBubble.ets        # 聊天气泡
│   ├── MarkdownView.ets      # Markdown 渲染
│   ├── TypingView.ets        # 打字机效果
│   ├── PromptCard.ets        # Prompt 卡片
│   ├── AIAvatar.ets          # AI 头像
│   ├── MessageItem.ets       # 消息列表项
│   ├── InputBar.ets          # 输入栏
│   ├── ModelSelector.ets     # 模型选择器
│   ├── LoadingView.ets       # 加载动画
│   ├── HistoryCard.ets       # 历史卡片
│   ├── CodeBlock.ets         # 代码块
│   ├── Toolbar.ets           # 工具栏
│   ├── ImagePicker.ets       # 图片选择器
│   ├── OCRCard.ets           # OCR 结果卡片
│   └── SettingItem.ets       # 设置项
├── common/                   # 公共模块
│   ├── Logger.ts             # 日志工具
│   ├── Constants.ts          # 全局常量
│   └── Types.ts              # 全局类型定义
├── repository/               # 数据仓库层
│   ├── ChatRepository.ts     # 聊天数据仓库
│   ├── ConversationRepository.ts # 会话仓库
│   ├── PromptRepository.ts   # Prompt 仓库
│   └── SettingsRepository.ts # 设置仓库
├── service/                  # 服务层
│   └── AIService.ts          # AI 服务统一入口
├── provider/                 # LLM Provider
│   ├── LLMProvider.ts        # Provider 接口
│   ├── OpenAIProvider.ts     # OpenAI
│   ├── DeepSeekProvider.ts   # DeepSeek
│   ├── QwenProvider.ts       # 通义千问
│   ├── ZhipuProvider.ts      # 智谱 AI
│   └── DoubaoProvider.ts     # 豆包
├── ai/                       # AI 能力模块
│   ├── ChatManager.ts        # 聊天管理
│   ├── TranslateManager.ts   # 翻译管理
│   ├── OCRManager.ts         # OCR 管理
│   ├── SummaryManager.ts     # 总结管理
│   ├── FlowerManager.ts      # 花语管理
│   ├── TodoManager.ts        # 待办管理
│   ├── ScheduleManager.ts    # 日程管理
│   └── CodeManager.ts        # 代码解释管理
├── prompt/                   # Prompt 管理
│   ├── PromptManager.ts      # Prompt 管理器
│   └── templates/            # Prompt 模板文件
│       ├── chat.md
│       ├── translate.md
│       ├── flower.md
│       ├── summary.md
│       ├── todo.md
│       ├── schedule.md
│       ├── code.md
│       └── system.md
├── model/                    # 数据模型
│   ├── ChatMessage.ts        # 聊天消息
│   ├── Conversation.ts       # 会话
│   ├── Prompt.ts             # Prompt
│   ├── ModelConfig.ts        # 模型配置
│   └── AIResponse.ts         # AI 响应
├── database/                 # 数据库
│   ├── DatabaseManager.ts    # 数据库管理器
│   └── tables/               # 表定义
├── theme/                    # 主题管理
│   ├── ThemeManager.ts       # 主题管理器
│   ├── LightTheme.ts         # 浅色主题
│   └── DarkTheme.ts          # 深色主题
├── constants/                # 常量
│   ├── AppConstants.ts       # 应用常量
│   └── ApiConstants.ts       # API 常量
└── utils/                    # 工具类
    ├── AIUtil.ts             # AI 工具
    ├── MarkdownUtil.ts       # Markdown 工具
    ├── PromptUtil.ts         # Prompt 工具
    ├── JsonUtil.ts           # JSON 工具
    ├── ImageUtil.ts          # 图片工具
    ├── OCRUtil.ts            # OCR 工具
    ├── RouterUtil.ts         # 路由工具
    ├── ToastUtil.ts          # Toast 工具
    ├── ThemeUtil.ts          # 主题工具
    └── PreferenceUtil.ts     # 偏好存储工具

完整的目录结构包含 18 个一级目录、30+ 个页面和组件、10+ 工具类,覆盖了企业级 AI 应用的所有模块。


三、核心配置文件

3.1 build-profile.json5(顶层)

{
  "app": {
    "products": [
      {
        "name": "default",
        "signingConfig": "default"
      }
    ],
    "buildSettings": {
      "compatibleSdkVersion": "5.0.0",
      "compileSdkVersion": "5.0.0",
      "targetSdkVersion": "5.0.0"
    }
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "buildProfile": "./entry/build-profile.json5"
    }
  ]
}

3.2 module.json5(Entry 模块)

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "HarmonyAI 主模块",
    "mainAbility": "EntryAbility",
    "deviceTypes": ["phone"],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ts",
        "description": "应用主入口",
        "icon": "$media:app_icon",
        "label": "$string:app_name",
        "startWindowIcon": "$media:app_icon",
        "startWindowBackground": "$color:start_window_background"
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.READ_MEDIA"
      },
      {
        "name": "ohos.permission.CAMERA"
      }
    ]
  }
}

注意:INTERNET 权限用于 AI API 调用,READ_MEDIA 和 CAMERA 用于 OCR 图片识别功能。

3.3 oh-package.json5(Entry 模块)

{
  "name": "entry",
  "version": "1.0.0",
  "description": "HarmonyAI entry module",
  "dependencies": {
    "@ohos/axios": "^2.2.0",
    "@ohos/data-preferences": "^1.0.0",
    "@ohos/data.persistence": "^1.0.0",
    "@ohos.multimedia.image": "^1.0.0",
    "@ohos.multimedia.camera": "^1.0.0",
    "@kit.MediaLibraryKit": "^1.0.0"
  }
}

四、创建首个验证页面

4.1 EntryAbility 入口

// entryability/EntryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import display from '@ohos.display';

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    hilog.info(0x0000, 'HarmonyAI', 'Ability onCreate');
  }

  onDestroy() {
    hilog.info(0x0000, 'HarmonyAI', 'Ability onDestroy');
  }

  async onWindowStageCreate(windowStage: window.WindowStage) {
    hilog.info(0x0000, 'HarmonyAI', 'onWindowStageCreate');

    // 安全区处理:获取状态栏和导航栏高度并转换为 vp
    await this.initSafeArea();

    windowStage.loadContent('pages/SplashPage', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'HarmonyAI', 'Failed to load content. Cause: %{public}s',
          JSON.stringify(err));
        return;
      }
      hilog.info(0x0000, 'HarmonyAI', 'Succeeded in loading content');
    });
  }

  // 初始化安全区高度
  private async initSafeArea(): Promise<void> {
    try {
      const defaultDisplay = display.getDefaultDisplaySync();
      const densityPixels = defaultDisplay.densityPixels;

      // 获取窗口实例
      const windowClass = await window.getLastWindow(this.context);

      // 获取状态栏高度(px 转 vp)
      const statusBarHeightPx = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height;
      const statusBarHeight = statusBarHeightPx / densityPixels;

      // 获取导航栏高度(px 转 vp)
      const navBarHeightPx = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR).bottomRect.height;
      const navBarHeight = navBarHeightPx / densityPixels;

      // 存储到 AppStorage,供所有页面共享
      AppStorage.setOrCreate<number>('statusBarHeight', statusBarHeight);
      AppStorage.setOrCreate<number>('navBarHeight', navBarHeight);

      hilog.info(0x0000, 'HarmonyAI',
        'SafeArea statusBar: %{public}.2f vp, navBar: %{public}.2f vp',
        statusBarHeight, navBarHeight);
    } catch (error) {
      hilog.error(0x0000, 'HarmonyAI',
        'Failed to init safe area: %{public}s', error.message);
      // 使用默认值兜底
      AppStorage.setOrCreate<number>('statusBarHeight', 32);
      AppStorage.setOrCreate<number>('navBarHeight', 24);
    }
  }

  onWindowStageDestroy() {
    hilog.info(0x0000, 'HarmonyAI', 'onWindowStageDestroy');
  }

  onForeground() {
    hilog.info(0x0000, 'HarmonyAI', 'onForeground');
  }

  onBackground() {
    hilog.info(0x0000, 'HarmonyAI', 'onBackground');
  }
}

4.2 启动页(SplashPage)

// pages/SplashPage.ets
@Entry
@Component
struct SplashPage {
  @State opacityValue: number = 0;
  @State scaleValue: number = 0.8;

  aboutToAppear() {
    // 启动动画
    animateTo({ duration: 1000, curve: Curve.FastOutSlowIn }, () => {
      this.opacityValue = 1;
      this.scaleValue = 1;
    });

    // 延迟跳转首页
    setTimeout(() => {
      RouterUtil.navigateTo('pages/HomePage');
    }, 2000);
  }

  build() {
    Column() {
      // Logo
      Image($r('app.media.app_icon'))
        .width(120)
        .height(120)
        .opacity(this.opacityValue)
        .scale({ x: this.scaleValue, y: this.scaleValue })
      // 应用名称
      Text($r('app.string.app_name'))
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 24 })
        .opacity(this.opacityValue)
      // 应用描述
      Text('AI 智能生活助手')
        .fontSize(16)
        .fontColor(Color.Gray)
        .margin({ top: 8 })
        .opacity(this.opacityValue)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor($r('app.color.splash_background'));
  }
}

4.3 验证编译

在 DevEco Studio 中,执行以下验证:

# 1. 清理项目
hvigorw clean

# 2. 编译 HAP
hvigorw assembleHap

# 3. 编译成功输出
> BUILD SUCCESSFUL in 30s

出现 BUILD SUCCESSFUL 说明项目创建成功,企业级目录结构搭建完成。


五、Git 初始化

5.1 创建 .gitignore

# HarmonyOS
.idea/
.gradle/
build/
local.properties
*.hprof
*.iml

# Node
node_modules/
.hvigor/

# OS
.DS_Store
Thumbs.db

# IDE
*.swp
*.swo

5.2 初始化 Git 仓库

# 初始化仓库
git init

# 添加文件
git add .

# 首次提交
git commit -m "feat(init): 初始化企业级 AI 工程

- 创建 HarmonyOS NEXT 基础工程
- 搭建 18 个模块的企业级目录结构
- 配置 build-profile.json5、module.json5
- 实现启动页与基本动画
- 配置 Git 版本管理

Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>"

# 创建 Tag
git tag v0.0.1

六、验证清单

6.1 项目结构完整性检查

检查项要求状态
一级目录18 个✅
页面文件12 个✅
组件文件15 个✅
工具类10 个✅
Provider5 个✅
Prompt 模板8 个✅
数据模型5 个✅
配置文件3 个✅

6.2 编译运行检查

  1. DevEco Studio 打开项目无错误
  2. hvigorw assembleHap 编译成功
  3. 启动页 动画正常显示
  4. 路由跳转 到首页正常

如果以上检查项全部通过,说明企业级工程创建成功!


七、企业级目录结构最佳实践

7.1 分层依赖规则

各层的依赖关系必须遵循以下规则:

pages/ → components/ → common/
pages/ → repository/ → service/ → provider/
service/ → ai/ → prompt/
repository/ → database/
components/ → theme/ → constants/

禁止 页面层直接调用 Provider 或 PromptManager,必须通过 AIService 统一封装。

7.2 模块职责矩阵

模块对外暴露内部依赖禁止依赖
pages页面组件components, repositoryprovider, ai
componentsUI 组件theme, constantsrepository, service
repository数据接口database, modelpages, components
serviceAI 服务provider, ai, promptpages, components
providerLLM 接口constants业务层
promptPrompt 模板无无
model类型定义无无

7.3 命名规范

// 1. 文件命名:大驼峰
// 正确:ChatPage.ets, AIService.ts
// 错误:chatPage.ets, ai_service.ts

// 2. 类/接口命名:大驼峰
interface ChatMessage {}
class AIService {}

// 3. 方法命名:小驼峰
sendMessage()
loadPrompts()

// 4. 常量命名:全大写 + 下划线
const API_BASE_URL = 'https://api.example.com'
const MAX_RETRY_COUNT = 3

7.4 HarmonyOS NEXT 开发关键注意事项

在企业级 HarmonyOS NEXT 开发中,以下细节直接影响应用的稳定性和用户体验:

1. 安全区适配

所有页面必须通过 AppStorage 获取安全区高度,避免内容被状态栏或导航栏遮挡:

// pages/AnyPage.ets
@Entry
@Component
struct AnyPage {
  // 从 AppStorage 读取安全区高度
  @StorageLink('statusBarHeight') statusBarHeight: number = 32;
  @StorageLink('navBarHeight') navBarHeight: number = 24;

  build() {
    Column() {
      // 顶部占位,避开状态栏
      Row().width('100%').height(this.statusBarHeight);

      // 页面内容...

      // 底部占位,避开导航栏
      Row().width('100%').height(this.navBarHeight);
    }
    .width('100%')
    .height('100%');
  }
}

2. SVG 矢量图标

HarmonyOS NEXT 设备上,emoji 会渲染为蓝色或紫色块,必须使用 SVG 矢量图替代:

用途错误做法正确做法
功能图标使用 emoji(如 🔍)使用 SVG(如 $r('app.media.ic_search'))
状态标识使用 emoji(如 ✅)使用 SVG(如 $r('app.media.ic_check'))
装饰元素使用 emoji(如 🌟)使用 SVG(如 $r('app.media.ic_star'))

重要:所有图标资源应放在 resources/base/media 目录下,统一使用 Image($r('app.media.xxx')) 加载。

3. 文件操作模式

HarmonyOS NEXT 中文件打开模式使用 fs.OpenMode.READ_ONLY,注意不是 READONLY:

// 正确
const file = await fs.open(filePath, fs.OpenMode.READ_ONLY);

// 错误
const file = await fs.open(filePath, fs.OpenMode.READONLY); // 不存在此枚举

八、常见问题

8.1 编译报错:module.json5 权限不足

// 错误:缺少 INTERNET 权限
// 症状:网络请求失败,hilog 提示 "Permission denied"

// 解决方案:在 module.json5 中添加
{
  "name": "ohos.permission.INTERNET"
}

8.2 目录引用路径问题

// 错误:使用相对路径引用
import { AIService } from '../../service/AIService'

// 正确:使用相对路径从 ets 开始
import { AIService } from '../service/AIService'

提示:HarmonyOS NEXT 的模块解析规则为:相对路径从当前文件的所在目录开始计算。


九、下一步开发计划

工程创建完成后,下一篇将进行 首页设计与开发:

  1. 快捷入口网格布局
  2. 最近聊天列表
  3. AI 推荐卡片
  4. 每日一句展示
  5. 今日花语 Widget

总结

本文详细介绍了如何创建一个 企业级 的 HarmonyOS NEXT AI 工程。核心要点:

  1. 两阶段创建:基础工程 → 企业级目录结构
  2. 18 个模块目录:分层清晰,职责明确
  3. 核心配置:build-profile.json5、module.json5、oh-package.json5
  4. 首个页面验证:启动页确认项目可编译运行
  5. Git 初始化:版本控制与 Tag 管理

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


上一篇: [项目规划与架构设计]

下一篇: [首页设计与快捷入口实现]

相关资源:

Logo

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

更多推荐