HarmonyOS NEXT 实战:从零开发一款密码生成器应用

HarmonyOS NEXT 实战:从零开发一款密码生成器应用

包名:com.example.myapplication

开发工具:DevEco Studio


一、前言:为什么开发密码生成器?

在数字化时代,密码安全已成为每个人必须面对的问题。弱密码、重复使用密码是导致账户被盗的主要原因之一。作为一名鸿蒙开发者,我决定利用 HarmonyOS NEXT 的 ArkTS 声明式UI框架,开发一款简洁实用的密码生成器应用。

这个项目虽然功能相对简单,但涵盖了鸿蒙开发的多个核心知识点:

  • 状态管理@State 装饰器的使用
  • 用户交互:Toggle开关、Button按钮事件处理
  • 业务逻辑:随机算法、密码强度计算
  • UI布局:Column/Row布局、样式美化

本文将详细记录从项目创建到功能实现的完整过程,希望对正在学习鸿蒙开发的同学有所帮助。


二、项目初始化

2.1 创建项目

打开 DevEco Studio,选择 File → New → Create Project ,选择 Empty Ability 模板:

  • 项目名称:MyApplication
  • Bundle Name:com.example.myapplication
  • Compile SDK:API 12(HarmonyOS NEXT)
  • Model:Stage 模型(推荐)

点击 Finish 完成创建,DevEco Studio 会自动生成项目骨架。

2.2 项目结构解析

创建完成后的项目结构如下:

复制代码
MyApplication/
├── AppScope/                    # 应用全局配置
│   ├── app.json5               # 应用配置(bundleName、版本等)
│   └── resources/              # 全局资源
├── entry/                       # 主模块
│   ├── src/main/
│   │   ├── ets/
│   │   │   ├── entryability/   # 应用入口能力
│   │   │   │   └── EntryAbility.ets
│   │   │   └── pages/          # 页面目录
│   │   │       └── Index.ets   # 主页面
│   │   ├── resources/          # 资源文件
│   │   │   ├── base/element/   # 字符串、颜色等
│   │   │   └── base/media/     # 图片资源
│   │   └── module.json5        # 模块配置
│   └── build-profile.json5     # 构建配置
└── build-profile.json5         # 项目构建配置

关键文件说明

文件 作用
app.json5 应用全局配置,包括包名、版本号、图标等
module.json5 模块配置,定义Ability、页面路由等
EntryAbility.ets 应用入口,类似Android的Application
Index.ets 主页面UI代码

三、功能设计

3.1 功能需求

本应用需要实现以下功能:

  1. 密码生成:根据用户选择的字符类型随机生成密码
  2. 长度调节:支持4-24位密码长度调节
  3. 字符类型选择:支持大写字母、小写字母、数字、特殊符号四种类型
  4. 密码强度检测:实时显示密码强度(弱/中/强)
  5. 一键复制:生成后可复制到剪贴板

3.2 UI设计

采用卡片式布局,整体风格简洁现代:

复制代码
┌─────────────────────────────┐
│      🔐 密码生成器          │  ← 标题区
│    生成高强度随机密码        │
├─────────────────────────────┤
│                             │
│     [生成的密码显示区]       │  ← 结果展示
│      [强度指示条]           │
│                             │
├─────────────────────────────┤
│       密码长度              │
│    [ - ]  12  [ + ]        │  ← 长度调节
├─────────────────────────────┤
│       字符类型              │
│   A-Z        [开关]        │
│   a-z        [开关]        │  ← 类型选择
│   0-9        [开关]        │
│   !@#$%      [开关]        │
├─────────────────────────────┤
│    [ 🔄 生成密码 ]          │  ← 操作按钮
│    [ 📋 复制密码 ]          │
└─────────────────────────────┘

四、核心代码实现

4.1 状态变量定义

使用 @State 装饰器定义响应式状态变量:

typescript 复制代码
@Entry
@Component
struct Index {
  // 密码结果
  @State password: string = '点击生成';
  
  // 密码长度
  @State passwordLength: number = 12;
  
  // 字符类型开关
  @State hasUpper: boolean = true;   // 大写字母
  @State hasLower: boolean = true;   // 小写字母
  @State hasNumber: boolean = true;  // 数字
  @State hasSymbol: boolean = false; // 特殊符号
  
  // 复制提示
  @State showCopyTip: boolean = false;

  // 字符集常量
  readonly upperChars: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  readonly lowerChars: string = 'abcdefghijklmnopqrstuvwxyz';
  readonly numberChars: string = '0123456789';
  readonly symbolChars: string = '!@#$%^&*()_+-=[]{}|;:,.<>?';
}

知识点

  • @State 装饰的变量变化时,UI会自动刷新
  • readonly 用于定义不可变常量
  • 命名规范:布尔类型变量用 has/is 前缀

4.2 密码生成算法

typescript 复制代码
generatePassword(): void {
  // 1. 根据选择组装字符池
  let chars: string = '';
  if (this.hasUpper) chars += this.upperChars;
  if (this.hasLower) chars += this.lowerChars;
  if (this.hasNumber) chars += this.numberChars;
  if (this.hasSymbol) chars += this.symbolChars;

  // 2. 校验:至少选择一种类型
  if (chars.length === 0) {
    this.password = '⚠️ 请选择至少一种字符类型';
    return;
  }

  // 3. 随机生成
  let result: string = '';
  for (let i: number = 0; i < this.passwordLength; i++) {
    const randomIndex: number = Math.floor(Math.random() * chars.length);
    result += chars[randomIndex];
  }
  
  this.password = result;
  this.showCopyTip = false; // 重置复制提示
}

算法解析

  1. 先根据用户选择的类型拼接可用字符集
  2. 如果没有选择任何类型,给出提示
  3. 使用 Math.random() 生成随机索引,循环拼接字符

4.3 密码强度检测

typescript 复制代码
getStrengthLevel(): string {
  // 统计启用的字符类型数量
  let types: number = 0;
  if (this.hasUpper) types++;
  if (this.hasLower) types++;
  if (this.hasNumber) types++;
  if (this.hasSymbol) types++;

  // 强度判断逻辑
  if (this.passwordLength >= 16 && types >= 3) {
    return 'strong';  // 长度≥16且包含3种以上类型
  } else if (this.passwordLength >= 10 && types >= 2) {
    return 'medium';  // 长度≥10且包含2种以上类型
  }
  return 'weak';      // 其他情况
}

getStrengthText(): string {
  const level = this.getStrengthLevel();
  if (level === 'strong') return '🔒 强';
  if (level === 'medium') return '🔐 中';
  return '🔓 弱';
}

getStrengthColor(): string {
  const level = this.getStrengthLevel();
  if (level === 'strong') return '#34C759';  // 绿色
  if (level === 'medium') return '#FF9500';  // 橙色
  return '#FF3B30';                           // 红色
}

getStrengthWidth(): number {
  const level = this.getStrengthLevel();
  if (level === 'strong') return 100;
  if (level === 'medium') return 60;
  return 30;
}

强度判断规则

强度 条件 颜色
长度≥16 且 包含≥3种字符类型 🟢 绿色
长度≥10 且 包含≥2种字符类型 🟠 橙色
其他情况 🔴 红色

4.4 长度调节功能

typescript 复制代码
increaseLength(): void {
  if (this.passwordLength < 24) {
    this.passwordLength++;
  }
}

decreaseLength(): void {
  if (this.passwordLength > 4) {
    this.passwordLength--;
  }
}

UI部分使用圆形按钮配合加减号:

typescript 复制代码
Row() {
  Button('-')
    .type(ButtonType.Circle)
    .width(36)
    .height(36)
    .backgroundColor('#007AFF')
    .onClick(() => {
      this.decreaseLength();
    })

  Text(`${this.passwordLength}`)
    .fontSize(28)
    .fontWeight(FontWeight.Bold)
    .width(60)

  Button('+')
    .type(ButtonType.Circle)
    .width(36)
    .height(36)
    .backgroundColor('#007AFF')
    .onClick(() => {
      this.increaseLength();
    })
}
.justifyContent(FlexAlign.Center)

4.5 字符类型选择

使用 Toggle 组件实现开关切换:

typescript 复制代码
Column({ space: 10 }) {
  // 大写字母
  Row() {
    Text('A-Z').fontSize(16).fontColor('#1C1C1E')
    Blank()
    Toggle({ type: ToggleType.Switch, isOn: this.hasUpper })
      .selectedColor('#34C759')
      .onChange((value: boolean) => {
        this.hasUpper = value;
      })
  }
  .width('100%')

  // 小写字母
  Row() {
    Text('a-z').fontSize(16).fontColor('#1C1C1E')
    Blank()
    Toggle({ type: ToggleType.Switch, isOn: this.hasLower })
      .selectedColor('#34C759')
      .onChange((value: boolean) => {
        this.hasLower = value;
      })
  }
  .width('100%')

  // 数字
  Row() {
    Text('0-9').fontSize(16).fontColor('#1C1C1E')
    Blank()
    Toggle({ type: ToggleType.Switch, isOn: this.hasNumber })
      .selectedColor('#34C759')
      .onChange((value: boolean) => {
        this.hasNumber = value;
      })
  }
  .width('100%')

  // 特殊符号
  Row() {
    Text('!@#$%').fontSize(16).fontColor('#1C1C1E')
    Blank()
    Toggle({ type: ToggleType.Switch, isOn: this.hasSymbol })
      .selectedColor('#34C759')
      .onChange((value: boolean) => {
        this.hasSymbol = value;
      })
  }
  .width('100%')
}
.padding(16)
.backgroundColor('#F2F2F7')
.borderRadius(16)

Toggle组件属性

  • type: ToggleType.Switch:开关样式
  • isOn:绑定布尔状态
  • selectedColor:选中时的颜色
  • onChange:状态变化回调

4.6 复制功能实现

typescript 复制代码
copyPassword(): void {
  // 校验:空值或提示文字不可复制
  if (this.password === '' || 
      this.password === '点击生成' || 
      this.password.startsWith('⚠️')) {
    return;
  }
  
  this.showCopyTip = true;
  
  // 2秒后隐藏提示
  const timer = setTimeout(() => {
    this.showCopyTip = false;
    clearTimeout(timer);
  }, 2000);
}

注意 :HarmonyOS 的剪贴板API需要在真机上测试,模拟器可能不完全支持。本示例仅展示提示效果,实际项目中可使用 @ohos.pasteboard 模块实现真正的复制功能。


五、完整UI布局

5.1 密码显示区域

typescript 复制代码
Column() {
  Text(this.password)
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
    .fontColor('#1C1C1E')
    .textAlign(TextAlign.Center)
    .lineHeight(28)
    .width('100%')

  // 强度指示条
  if (this.password !== '点击生成' && !this.password.startsWith('⚠️')) {
    Row() {
      Row() {
        Text(this.getStrengthText())
          .fontSize(12)
          .fontColor('#FFFFFF')
          .fontWeight(FontWeight.Bold)
      }
      .width(this.getStrengthWidth() + 20)
      .height(22)
      .backgroundColor(this.getStrengthColor())
      .borderRadius(11)
      .justifyContent(FlexAlign.Center)
      .margin({ top: 8 })
    }
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }

  // 复制提示
  if (this.showCopyTip) {
    Text('✓ 已复制到剪贴板')
      .fontSize(12)
      .fontColor('#34C759')
      .margin({ top: 4 })
  }
}
.width('100%')
.padding(20)
.backgroundColor('#F2F2F7')
.borderRadius(16)
.margin({ bottom: 24 })

5.2 操作按钮

typescript 复制代码
// 生成按钮
Button('🔄 生成密码')
  .type(ButtonType.Capsule)
  .width(240)
  .height(52)
  .backgroundColor('#007AFF')
  .fontSize(18)
  .fontWeight(FontWeight.Bold)
  .onClick(() => {
    this.generatePassword();
  })

// 复制按钮
Button('📋 复制密码')
  .type(ButtonType.Capsule)
  .width(240)
  .height(44)
  .backgroundColor('#34C759')
  .fontSize(16)
  .fontWeight(FontWeight.Medium)
  .margin({ top: 10 })
  .onClick(() => {
    this.copyPassword();
  })

5.3 整体布局结构

typescript 复制代码
build() {
  Column() {
    // 1. 标题区
    Text('🔐 密码生成器')
      .fontSize(26)
      .fontWeight(FontWeight.Bold)
      .fontColor('#1C1C1E')
      .margin({ top: 30, bottom: 4 })
    Text('生成高强度随机密码')
      .fontSize(14)
      .fontColor('#8E8E93')
      .margin({ bottom: 24 })

    // 2. 密码显示区
    // ...(见5.1)

    // 3. 密码长度调节
    // ...(见4.4)

    // 4. 字符类型选择
    // ...(见4.5)

    // 5. 操作按钮
    // ...(见5.2)
  }
  .width('100%')
  .height('100%')
  .backgroundColor('#FFFFFF')
  .padding(20)
  .alignItems(HorizontalAlign.Center)
}

六、配置文件修改

6.1 字符串资源

修改 entry/src/main/resources/base/element/string.json

json 复制代码
{
  "string": [
    {
      "name": "module_desc",
      "value": "密码生成器"
    },
    {
      "name": "EntryAbility_desc",
      "value": "生成高强度随机密码"
    },
    {
      "name": "EntryAbility_label",
      "value": "密码生成器"
    }
  ]
}

6.2 颜色资源

修改 entry/src/main/resources/base/element/color.json

json 复制代码
{
  "color": [
    {
      "name": "start_window_background",
      "value": "#FFFFFF"
    }
  ]
}

6.3 模块配置

module.json5 已由DevEco Studio自动生成,关键配置:

json5 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "deviceTypes": ["phone"],
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["ohos.want.action.home"]
          }
        ]
      }
    ]
  }
}

七、运行效果

八、踩坑记录

8.1 踩坑一:Toggle组件状态不同步

问题 :Toggle的 isOn 属性绑定状态变量后,有时UI显示与实际值不一致。

解决 :确保 onChange 回调中正确更新状态,并使用箭头函数保持 this 指向:

typescript 复制代码
Toggle({ type: ToggleType.Switch, isOn: this.hasUpper })
  .onChange((value: boolean) => {
    this.hasUpper = value;  // 正确更新
  })

8.2 踩坑二:密码强度不更新

问题:修改字符类型后,强度指示条没有实时更新。

解决 :密码强度的计算依赖于多个状态变量,ArkTS会自动追踪依赖关系。确保 getStrengthLevel() 方法中正确读取所有相关状态即可。

8.3 踩坑三:Button样式继承问题

问题:两个按钮样式不一致,一个圆角一个方形。

解决 :显式指定 type 属性:

typescript 复制代码
Button('生成密码')
  .type(ButtonType.Capsule)  // 胶囊形状

8.4 踩坑四:条件渲染失效

问题:强度指示条有时不显示。

解决:条件判断要完整,避免空值或特殊字符:

typescript 复制代码
if (this.password !== '点击生成' && !this.password.startsWith('⚠️')) {
  // 渲染强度指示条
}

九、优化建议

9.1 功能扩展

  1. 密码历史记录 :使用 @ohos.data.preferences 持久化存储历史密码
  2. 自定义字符集:允许用户自定义特殊符号集
  3. 密码规则预设:提供"银行级"、"网站级"等预设配置
  4. 批量生成:一次生成多个密码供选择

9.2 UI优化

  1. 暗黑模式支持:通过系统配置自动切换深色主题
  2. 动画效果:生成密码时添加动画,提升用户体验
  3. 触觉反馈:生成密码时震动提示

9.3 安全增强

  1. 真随机数 :使用 @ohos.crypto 模块生成加密级随机数
  2. 剪贴板清理:复制后定时清除剪贴板内容

十、总结

通过这个密码生成器项目,我深入实践了 HarmonyOS NEXT 的 ArkTS 声明式UI开发,掌握了以下核心技能:

知识点 应用场景
@State 状态管理 密码、长度、开关等响应式数据
Column/Row布局 整体页面结构搭建
Toggle组件 字符类型开关选择
Button组件 生成、复制等操作按钮
条件渲染 强度指示条、复制提示
样式美化 圆角、颜色、间距等

项目亮点

  • ✅ 代码简洁,单文件实现全部功能(约200行)
  • ✅ UI美观,采用现代卡片式设计
  • ✅ 交互友好,实时反馈密码强度
  • ✅ 可扩展性强,易于添加新功能

HarmonyOS NEXT 的 ArkTS 语法与 TypeScript 高度一致,学习成本低,开发效率高。声明式UI让界面与数据自动同步,大大减少了手动更新的代码量。如果你也在学习鸿蒙开发,建议从这类小项目入手,逐步积累经验。


相关推荐
李二。1 小时前
鸿蒙原生ArkTS布局方式之ColumnBaseline垂直排列
华为·harmonyos
yuegu7771 小时前
HarmonyOS应用<节气通>开发第8篇:知识百科页开发
华为·harmonyos
想你依然心痛2 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“航界智脑“——PC端AI智能体沉浸式无人机集群任务规划与空域协同管理工作台
人工智能·ar·无人机·harmonyos·智能体
李二。2 小时前
鸿蒙原生ArkTS布局方式之ColumnCenter垂直排列
华为·harmonyos
不爱吃糖的程序媛3 小时前
@capacitor/camera 插件在鸿蒙PC平台的适配实践
华为·harmonyos
想你依然心痛3 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“链界智脑“——PC端AI智能体沉浸式区块链智能合约审计与DeFi风控管理工作台
人工智能·区块链·ar·harmonyos·智能体
夜勤月3 小时前
深入解析 HarmonyOS 6 悬浮导航 2.0 与沉浸光感引擎
华为·harmonyos
yuegu7773 小时前
HarmonyOS应用<节气通>开发第7篇:文章详情页开发
华为·harmonyos
李二。3 小时前
鸿蒙原生ArkTS布局方式之ColumnEnd垂直排列
华为·harmonyos