【鸿蒙原生开发实战】第五篇:主题切换与发布准备——深色模式、设置页面、签名与构建

前言

经过前面四篇的开发,「知墨」笔记应用的核心功能已经完备。但一个完整的应用还需要:

  1. 深色/浅色主题切换——提升用户体验
  2. 设置页面——整合数据管理功能
  3. Seed 数据——方便初次体验
  4. 构建与签名——生成可发布的 HAP 包

本篇是系列的收官之作,我们将完成以上所有内容,把一个开发中的项目变成可交付的应用。


一、深色/浅色主题切换

1.1 主题架构设计

主题切换涉及三个层面:

层面 实现方式 影响范围
系统级 setColorMode() 系统控件(状态栏、对话框)
颜色资源 $r('app.color.xxx') 所有引用了颜色资源的 UI 组件
自定义状态 AppStorage 传递 theme 标志 业务组件的条件渲染

1.2 ThemeService 实现

前面第二篇已经介绍了 ThemeService 的初始化部分,这里聚焦切换逻辑:

async toggle(): Promise<boolean> {
  await this.setDarkMode(!this.isDark);
  return this.isDark;
}

private applyTheme(): void {
  AppStorage.setOrCreate('isDarkTheme', this.isDark);
  try {
    const ctx = AppStorage.get<Context>('appContext');
    if (ctx) {
      ctx.getApplicationContext().setColorMode(
        this.isDark
          ? ConfigurationConstant.ColorMode.COLOR_MODE_DARK
          : ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT,
      );
    }
  } catch (e) { /* ignore */ }
}

关键点

  • setColorMode() 是 ApplicationContext 的 API,必须通过应用级 Context 调用
  • AppStorage.setOrCreate('isDarkTheme', this.isDark) 将主题状态存入全局存储
  • 后续其他组件可以通过 @StorageProp('isDarkTheme') 监听主题变化

1.3 颜色资源文件

entry/src/main/resources/base/element/color.json 中定义了主题色板:

{
  "color": [
    { "name": "background", "value": "#FFF5F5F5" },
    { "name": "surface", "value": "#FFFFFFFF" },
    { "name": "surface_variant", "value": "#FFF0F0F3" },
    { "name": "primary", "value": "#FF6C5CE7" },
    { "name": "text_primary", "value": "#FF1A1A2E" },
    { "name": "text_secondary", "value": "#FF6C6C80" },
    { "name": "border", "value": "#FFE8E8EE" },
    { "name": "shadow", "value": "#0A000000" },
    { "name": "danger", "value": "#FFE17055" }
  ]
}

这是浅色主题的颜色定义。深色主题需要在 resources/dark/element/color.json 中覆盖:

{
  "color": [
    { "name": "background", "value": "#FF0D0D1A" },
    { "name": "surface", "value": "#FF1A1A2E" },
    { "name": "surface_variant", "value": "#FF252540" },
    { "name": "primary", "value": "#FF8B7CFA" },
    { "name": "text_primary", "value": "#FFEEEEF0" },
    { "name": "text_secondary", "value": "#FF9E9EB0" },
    { "name": "border", "value": "#FF2E2E45" },
    { "name": "shadow", "value": "#30000000" },
    { "name": "danger", "value": "#FFE17055" }
  ]
}

HarmonyOS 资源覆盖机制:系统会自动根据 setColorMode() 设置的主题加载对应 dark/base/ 目录下的资源,开发者只需要在 color.json 中定义好两套颜色,组件中用 $r('app.color.background') 引用即可。


二、SettingsPage 设置页面

2.1 页面组成

设置页面包含三个分组:

设置
├── 外观
│   ├── 深色模式 → [Switch 开关]
│   └── 笔记数量 → "共 X 篇笔记"
├── 数据管理
│   ├── [添加示例笔记] 按钮
│   └── [重置所有数据] 按钮
└── 关于
    ├── 应用名称 → 知墨
    ├── 版本 → 1.0.0
    └── 技术栈 → ArkTS + Preferences

2.2 深色模式开关

Row() {
  Column({ space: 4 }) {
    Text('深色模式').fontSize(15)
    Text('切换浅色/深色主题').fontSize(12)
      .fontColor($r('app.color.text_secondary'))
  }
  .layoutWeight(1)

  Toggle({ type: ToggleType.Switch, isOn: this.isDark })
    .onChange(() => { this.onToggleTheme(); })
}

ArkUI 的 Toggle({ type: ToggleType.Switch }) 提供了标准的 Switch 组件。isOn 参数控制开关状态。

2.3 示例数据填充

为了让用户第一次打开应用时有内容可看,SettingsPage 内置了 5 条示例笔记:

async onAddSampleData(): Promise<void> {
  const samples: string[][] = [
    ['HarmonyOS 开发入门', 'HarmonyOS 是华为开发的分布式操作系统...', 'tech', 'HarmonyOS,ArkTS'],
    ['周末爬山计划', '周六早上8点出发,带上水和干粮...', 'life', '运动,周末'],
    ['项目周报模板', '1. 本周完成事项\n2. 遇到的问题...', 'work', '工作,模板'],
    ['设计模式笔记:观察者模式', '观察者模式定义了对象之间的一对多依赖...', 'study', '设计模式,编程'],
    ['App 新功能构思', '1. 数据导出为 Markdown\n2. 笔记分享...', 'idea', '产品,功能'],
  ];
  for (const s of samples) {
    const tagList = s[3].split(',').map(t => t.trim());
    await noteUseCases.addNote(s[0], s[1], s[2], tagList);
  }
  await this.loadStats();
}

每条笔记覆盖了不同的分类(技术、生活、工作、学习、灵感),方便测试分类筛选功能。

2.4 数据重置

async onResetData(): Promise<void> {
  AlertDialog.show({
    title: '重置数据',
    message: `确定要清除全部 ${this.noteCount} 篇笔记吗?此操作不可撤销。`,
    primaryButton: { value: '取消', action: () => {} },
    secondaryButton: {
      value: '清除',
      action: async () => {
        const allNotes = await noteUseCases.getAllNotes();
        for (const note of allNotes) {
          await noteUseCases.deleteNote(note.id);
        }
        await noteUseCases.reload();
        await this.loadStats();
      }
    }
  });
}

设计考虑noteCount 动态显示当前笔记数量,让用户清楚重置会丢失多少数据。危险的"清除"按钮用红色($r('app.color.danger'))高亮警示。


三、color.json 完整配置

为了让主题切换生效,需要确保 entry/src/main/resources/ 目录下有以下结构:

resources/
├── base/
│   ├── element/
│   │   ├── color.json        # 浅色主题颜色
│   │   ├── string.json       # 字符串资源
│   │   └── boolean.json      # 布尔资源
│   ├── media/                # 图片资源
│   └── profile/
│       └── main_pages.json   # 页面路由注册
├── dark/
│   └── element/
│       └── color.json        # 深色主题颜色覆盖
├── en_US/                    # 英文资源(可选)
└── zh_CN/                    # 中文资源

四、构建 Release 包与签名

4.1 生成签名文件

在 DevEco Studio 中生成签名证书的步骤:

  1. 打开 Build → Generate Key and CSR

  2. 填写证书信息:

    • Alias: knowink_key
    • Validity: 25 years
    • Key Algorithm: RSA 2048
  3. 生成的 .p12 文件和 .csr 文件保存在项目 sign/ 目录下

4.2 配置签名

build-profile.json5 中添加签名配置:

{
  "app": {
    "signingConfigs": [
      {
        "name": "default",
        "material": {
          "storeFile": "./sign/knowink.p12",
          "storePassword": "your_password",
          "keyAlias": "knowink_key",
          "keyPassword": "your_password",
          "profileFile": "./sign/knowink_release.p7b",
          "certpath": "./sign/knowink_release.cer"
        }
      }
    ],
    // ...
  }
}

注意:实际密码不要明文提交到 Git。可以使用环境变量或 .gitignore 排除签名文件。我们项目中已经配置了 signingConfigs: [](空数组),请按需添加。

4.3 构建 HAP 包

# Debug 构建
hvigorw assembleHap --mode debug

# Release 构建(需要配置签名)
hvigorw assembleHap --mode release

构建产物位于:

entry/build/default/outputs/
├── default/
│   ├── entry-default-debug.hap      # Debug 包
│   └── entry-default-signed.hap     # 签名包(Release)
└── entry-default-unsigned.hap       # 未签名包

五、项目文件总览

至此,「知墨」笔记应用共包含 17 个源文件:

文件 行数(约) 职责
Domain models/Note.ts 32 笔记实体定义
models/Category.ts 22 分类定义
usecases/NoteUseCases.ts 52 业务用例编排
Data repositories/NoteRepository.ts 148 数据持久化仓库
services/PreferencesService.ts 40 Preferences 封装
services/ThemeService.ts 49 主题管理
UI core/NoteCard.ets 90 笔记卡片组件
core/StatsCard.ets 30 统计卡片组件
core/EmptyState.ets 25 空状态占位组件
core/CategoryBadge.ets 22 分类徽章组件
Pages Index.ets 228 主页面
NoteDetailPage.ets 199 笔记详情页
NoteEditPage.ets 184 新建/编辑页
SearchPage.ets 117 搜索页
SettingsPage.ets 199 设置页
Entry EntryAbility.ets 48 Ability 入口
EntryBackupAbility.ets - 备份 Ability

总代码量:约 1500 行 ArkTS 代码,实现了完整的笔记 CRUD、分类管理、搜索、主题切换等功能。


六、开发心得与避坑指南

6.1 构建踩坑回顾

问题 原因 解决方案
DEVECO_SDK_HOME Invalid daemon 缓存旧环境变量 --stop-daemon 后重试
build-profile.json5 not found 在错误目录执行 hvigorw cd 到项目根目录
EPERM mkdir 在工具目录下执行构建 在项目目录执行
Preferences 数据丢失 未调 flush() put 后显式调用 flush

6.2 后续可扩展方向

「知墨」目前是一个单机笔记应用,如果需要继续迭代,可以考虑:

  1. 数据云同步:基于华为云(AGConnect)的云数据库,实现多设备同步
  2. 富文本编辑:支持 Markdown 渲染
  3. 图片附件:使用 @kit.MediaLibraryKit 访问相册
  4. Widget 卡片:在桌面上展示最近笔记
  5. 语音输入:基于 @kit.VoiceCallKit 的语音转文字
  6. 分布式协同:利用 HarmonyOS 分布式数据管理在多设备间流转
    在这里插入图片描述
    在这里插入图片描述

七、系列总结

五篇博文路线图

第一篇:环境搭建与项目初始化
    ↓   DevEco Studio 安装、SDK 配置、hvigor 构建、项目结构
第二篇:数据层与核心架构
    ↓   Clean Architecture、领域模型、Repository、Preferences
第三篇:UI组件与主页开发
    ↓   CategoryBadge/StatsCard/NoteCard/EmptyState、主页面
第四篇:多页面路由与交互
    ↓   详情页、编辑页、搜索页、路由机制、表单校验
第五篇:主题切换与发布准备
    ↓   深色模式、设置页、签名、构建 HAP、项目总结

学习收获

通过「知墨」笔记应用的完整开发,我们实践了:

  • ArkTS 语言:interface、class、async/await、装饰器语法
  • ArkUI 声明式框架:@Component、@State、@Prop、build() 链式调用
  • 页面路由:router.pushUrl/back/getParams、页面注册
  • 数据持久化:Preferences API、JSON 序列化
  • 组件化设计:自定义组件拆分、Props 传递、回调函数
  • 主题管理:AppStorage、setColorMode、资源覆盖机制
  • 构建发布:hvigorw、签名配置、HAP 打包

开发环境:DevEco Studio 6.1 | HarmonyOS SDK 6.1.0 (API 23) | ArkTS + ArkUI

如果你对这个项目有任何问题或建议,欢迎在评论区讨论!

Logo

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

更多推荐