欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net


项目效果

本文实现的是一个基于 @ohos/crypto-js 的学习打卡口令摘要生成器。用户可以输入课程名称、学号、打卡日期和自定义口令,点击“生成摘要”按钮后,应用会将这些信息拼接成原始文本,并使用 SHA-256 和 MD5 生成对应的摘要结果。
请添加图片描述

页面主要包含以下内容:

  • 顶部标题:打卡摘要生成器;
  • 课程名称输入框;
  • 学号输入框;
  • 打卡日期输入框;
  • 自定义口令输入框;
  • 生成摘要按钮;
  • 填充示例按钮;
  • 清空按钮;
  • 原始拼接文本展示;
  • SHA-256 摘要结果展示;
  • MD5 摘要结果展示;
  • 页面整体采用卡片式布局。

这个页面可以作为学习打卡、签到校验、口令摘要、接口签名演示、数据完整性校验等项目的基础版本。


前言

在应用开发中,经常会遇到“把一段文本生成固定摘要”的需求。例如接口签名、数据校验、文件完整性验证、打卡口令生成等场景,都可能需要使用摘要算法。

摘要算法不是加密算法。它的作用是把一段输入内容转换成一段固定格式的字符串结果。常见的摘要算法包括 MD5、SHA-1、SHA-256 等。

需要注意的是,摘要结果一般不能反向还原出原文。也就是说,SHA-256 不是“把密码加密一下再解密回来”的工具。把摘要算法当加解密用,属于开发世界里很经典的自我伤害行为。

本篇文章选择使用 OpenHarmony 三方库 @ohos/crypto-js 来实现文本摘要生成功能。通过该库,可以较方便地对字符串生成 MD5 和 SHA-256 摘要。

本篇文章以“学习打卡口令摘要生成器”为场景,使用课程名称、学号、日期和口令拼接成原始文本,再通过 CryptoJS.SHA256()CryptoJS.MD5() 生成摘要结果,并结合 ArkUI 构建一个完整的工具页面。


一、项目目标

本次实践主要实现以下目标:

  • 在 OpenHarmony 项目中安装 @ohos/crypto-js 三方库;
  • 在 ArkTS 页面中引入并使用 CryptoJS
  • 使用 TextInput 接收打卡信息;
  • 将课程名称、学号、日期和口令拼接为原始文本;
  • 使用 SHA-256 生成摘要结果;
  • 使用 MD5 生成摘要结果;
  • 展示原始文本和摘要结果;
  • 使用 ArkUI 构建卡片式工具页面;
  • 实现填充示例、清空内容和状态提示;
  • 在 OpenHarmony 模拟器中完成运行验证。

二、技术栈

类型 内容
实战方向 Flutter for OpenHarmony 三方库实战
实现平台 OpenHarmony
开发语言 ArkTS
三方库 @ohos/crypto-js
使用算法 SHA-256 / MD5
功能场景 摘要生成 / 打卡口令 / 数据校验
UI 框架 ArkUI
开发工具 DevEco Studio
运行环境 OpenHarmony 模拟器

三、为什么选择 crypto-js

在实际项目中,摘要算法经常用于数据校验和签名场景。例如:

  • 生成接口签名;
  • 校验文本是否被修改;
  • 生成打卡口令摘要;
  • 对文件内容生成摘要;
  • 生成唯一标识辅助字段;
  • 校验本地缓存内容;
  • 处理简单的数据完整性验证。

如果自己实现 MD5 或 SHA-256 算法,代码复杂度会非常高,也不适合作为普通应用开发中的练习方向。使用成熟的三方库可以减少重复工作,把重点放在业务逻辑和页面实现上。

在本项目中,@ohos/crypto-js 主要用于:

  • 对原始打卡文本生成 SHA-256 摘要;
  • 对原始打卡文本生成 MD5 摘要;
  • 对比不同输入内容生成的摘要变化;
  • 演示摘要算法在 OpenHarmony 页面中的基本使用方式。

通过这个项目,可以比较直观地理解 OpenHarmony 中三方加密摘要库的接入方式。


四、安装 crypto-js 三方库

在项目根目录打开终端,执行以下命令:

ohpm install @ohos/crypto-js

安装完成后,可以检查项目中是否出现以下内容:

oh_modules
oh-package-lock.json5
oh-package.json5

如果依赖安装成功,就可以在 ArkTS 页面中引入:

import { CryptoJS } from '@ohos/crypto-js';

本项目主要使用以下方法:

方法 作用
CryptoJS.SHA256() 生成 SHA-256 摘要
CryptoJS.MD5() 生成 MD5 摘要
toString() 将摘要结果转换成字符串

五、项目结构

本次主要修改页面文件即可:

entry
 └── src
     └── main
         └── ets
             └── pages
                 └── Index.ets

如果你的项目中原本已经有 Index.ets,可以直接替换页面内容。

文件说明:

文件 作用
Index.ets 页面展示、打卡信息输入、摘要生成和结果渲染

本项目不需要请求远程接口,因此不需要配置网络权限。页面中的所有摘要生成操作都在本地完成。


六、页面状态设计

页面中主要使用以下状态变量:

@State courseName: string = '';
@State studentId: string = '';
@State checkDate: string = '';
@State secretCode: string = '';
@State rawText: string = '';
@State sha256Text: string = '';
@State md5Text: string = '';
@State resultText: string = '请输入打卡信息后生成摘要';
@State resultColor: string = '#999999';

字段说明如下:

状态变量 作用
courseName 保存课程名称
studentId 保存学号
checkDate 保存打卡日期
secretCode 保存自定义口令
rawText 保存拼接后的原始文本
sha256Text 保存 SHA-256 摘要
md5Text 保存 MD5 摘要
resultText 保存操作结果提示
resultColor 控制提示文字颜色

七、核心功能设计

本项目的核心流程如下:

  1. 用户输入课程名称;
  2. 用户输入学号;
  3. 用户输入打卡日期;
  4. 用户输入自定义口令;
  5. 点击“生成摘要”按钮;
  6. 将四项内容拼接成原始文本;
  7. 使用 SHA-256 生成摘要;
  8. 使用 MD5 生成摘要;
  9. 将原始文本和摘要结果展示到页面中。

原始文本拼接格式如下:

课程名称|学号|打卡日期|自定义口令

例如:

OpenHarmony应用开发|20260001|2026-05-11|study-hard

生成摘要的核心代码如下:

this.sha256Text = CryptoJS.SHA256(text).toString();
this.md5Text = CryptoJS.MD5(text).toString();

只要原始文本有任何变化,生成的摘要结果也会发生变化。


八、Index.ets 完整代码

打开文件:

entry/src/main/ets/pages/Index.ets

完整代码如下:

import { CryptoJS } from '@ohos/crypto-js';

@Entry
@Component
struct Index {
  @State courseName: string = '';
  @State studentId: string = '';
  @State checkDate: string = '';
  @State secretCode: string = '';
  @State rawText: string = '';
  @State sha256Text: string = '';
  @State md5Text: string = '';
  @State resultText: string = '请输入打卡信息后生成摘要';
  @State resultColor: string = '#999999';

  aboutToAppear(): void {
    this.fillSample();
    this.generateDigest();
  }

  fillSample(): void {
    this.courseName = 'OpenHarmony应用开发';
    this.studentId = '20260001';
    this.checkDate = '2026-05-11';
    this.secretCode = 'study-hard';
    this.resultText = '已填充示例数据,可以点击生成摘要进行测试';
    this.resultColor = '#0A59F7';
  }

  clearAll(): void {
    this.courseName = '';
    this.studentId = '';
    this.checkDate = '';
    this.secretCode = '';
    this.rawText = '';
    this.sha256Text = '';
    this.md5Text = '';
    this.resultText = '请输入打卡信息后生成摘要';
    this.resultColor = '#999999';
  }

  buildRawText(): string {
    return `${this.courseName.trim()}|${this.studentId.trim()}|${this.checkDate.trim()}|${this.secretCode.trim()}`;
  }

  generateDigest(): void {
    const course = this.courseName.trim();
    const student = this.studentId.trim();
    const date = this.checkDate.trim();
    const secret = this.secretCode.trim();

    if (course === '') {
      this.resultText = '课程名称不能为空';
      this.resultColor = '#E84026';
      return;
    }

    if (student === '') {
      this.resultText = '学号不能为空';
      this.resultColor = '#E84026';
      return;
    }

    if (date === '') {
      this.resultText = '打卡日期不能为空';
      this.resultColor = '#E84026';
      return;
    }

    if (secret === '') {
      this.resultText = '自定义口令不能为空';
      this.resultColor = '#E84026';
      return;
    }

    try {
      const text = this.buildRawText();
      this.rawText = text;
      this.sha256Text = CryptoJS.SHA256(text).toString();
      this.md5Text = CryptoJS.MD5(text).toString();
      this.resultText = '摘要生成成功';
      this.resultColor = '#00A870';
    } catch (error) {
      this.resultText = '摘要生成失败,请检查输入内容';
      this.resultColor = '#E84026';
    }
  }

  build() {
    Scroll() {
      Column() {
        Column() {
          Text('打卡摘要生成器')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')

          Text('基于 crypto-js 的学习打卡口令摘要页面')
            .fontSize(14)
            .fontColor('#666666')
            .margin({ top: 8 })
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding({
          left: 16,
          right: 16,
          top: 28,
          bottom: 12
        })

        Column() {
          Text('打卡信息')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          TextInput({
            placeholder: '请输入课程名称',
            text: this.courseName
          })
            .height(46)
            .fontSize(15)
            .backgroundColor('#FFFFFF')
            .borderRadius(12)
            .padding({
              left: 14,
              right: 14
            })
            .onChange((value: string) => {
              this.courseName = value;
            })

          TextInput({
            placeholder: '请输入学号',
            text: this.studentId
          })
            .height(46)
            .fontSize(15)
            .backgroundColor('#FFFFFF')
            .borderRadius(12)
            .padding({
              left: 14,
              right: 14
            })
            .margin({ top: 12 })
            .onChange((value: string) => {
              this.studentId = value;
            })

          TextInput({
            placeholder: '请输入打卡日期,例如 2026-05-11',
            text: this.checkDate
          })
            .height(46)
            .fontSize(15)
            .backgroundColor('#FFFFFF')
            .borderRadius(12)
            .padding({
              left: 14,
              right: 14
            })
            .margin({ top: 12 })
            .onChange((value: string) => {
              this.checkDate = value;
            })

          TextInput({
            placeholder: '请输入自定义口令',
            text: this.secretCode
          })
            .height(46)
            .fontSize(15)
            .backgroundColor('#FFFFFF')
            .borderRadius(12)
            .padding({
              left: 14,
              right: 14
            })
            .margin({ top: 12 })
            .onChange((value: string) => {
              this.secretCode = value;
            })

          Row() {
            Button('生成摘要')
              .fontSize(15)
              .height(42)
              .layoutWeight(1)
              .onClick(() => {
                this.generateDigest();
              })

            Button('填充示例')
              .fontSize(15)
              .height(42)
              .layoutWeight(1)
              .margin({ left: 10 })
              .onClick(() => {
                this.fillSample();
                this.generateDigest();
              })

            Button('清空')
              .fontSize(15)
              .height(42)
              .layoutWeight(1)
              .margin({ left: 10 })
              .onClick(() => {
                this.clearAll();
              })
          }
          .width('100%')
          .margin({ top: 16 })
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)

        Column() {
          Text('原始拼接文本')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          if (this.rawText === '') {
            Text('生成摘要后,这里会显示参与计算的原始文本。')
              .fontSize(15)
              .fontColor('#999999')
              .lineHeight(24)
          } else {
            Text(this.rawText)
              .fontSize(14)
              .fontColor('#333333')
              .lineHeight(24)
          }
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16,
          top: 16
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)

        Column() {
          Text('SHA-256 摘要结果')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          if (this.sha256Text === '') {
            Text('SHA-256 摘要会显示在这里')
              .fontSize(15)
              .fontColor('#999999')
              .lineHeight(24)
          } else {
            Text(this.sha256Text)
              .fontSize(13)
              .fontColor('#0A59F7')
              .lineHeight(22)
          }
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16,
          top: 16
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)

        Column() {
          Text('MD5 摘要结果')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          if (this.md5Text === '') {
            Text('MD5 摘要会显示在这里')
              .fontSize(15)
              .fontColor('#999999')
              .lineHeight(24)
          } else {
            Text(this.md5Text)
              .fontSize(13)
              .fontColor('#E84026')
              .lineHeight(22)
          }
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16,
          top: 16
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)

        Column() {
          Text('操作结果')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          Text(this.resultText)
            .fontSize(15)
            .fontColor(this.resultColor)
            .lineHeight(24)
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16,
          top: 16
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)

        Column() {
          Text('说明')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#182431')
            .margin({ bottom: 12 })

          Text('SHA-256 和 MD5 都属于摘要算法。摘要算法可以根据输入内容生成固定格式的结果,但不能直接反向还原原文。')
            .fontSize(14)
            .fontColor('#666666')
            .lineHeight(24)

          Text('如果任意输入内容发生变化,生成的摘要结果也会发生变化,因此可以用于简单的数据完整性校验演示。')
            .fontSize(14)
            .fontColor('#666666')
            .lineHeight(24)
            .margin({ top: 6 })
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)
        .padding(16)
        .margin({
          left: 16,
          right: 16,
          top: 16,
          bottom: 24
        })
        .backgroundColor('#F7F8FA')
        .borderRadius(18)
      }
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}

九、代码实现说明

1. 引入 crypto-js

页面顶部引入三方库:

import { CryptoJS } from '@ohos/crypto-js';

引入后,就可以使用 CryptoJS 提供的摘要算法方法。

本项目主要使用:

CryptoJS.SHA256()
CryptoJS.MD5()

2. 拼接原始文本

生成摘要前,先将课程名称、学号、打卡日期和自定义口令拼接成一段完整文本:

buildRawText(): string {
  return `${this.courseName.trim()}|${this.studentId.trim()}|${this.checkDate.trim()}|${this.secretCode.trim()}`;
}

这里使用 | 作为分隔符,方便看清楚每个字段的边界。

例如:

OpenHarmony应用开发|20260001|2026-05-11|study-hard

这段内容就是最终参与摘要计算的原始文本。


3. 生成 SHA-256 摘要

SHA-256 摘要生成代码如下:

this.sha256Text = CryptoJS.SHA256(text).toString();

SHA-256 生成的结果长度较长,更适合用来做数据完整性校验或签名演示。


4. 生成 MD5 摘要

MD5 摘要生成代码如下:

this.md5Text = CryptoJS.MD5(text).toString();

MD5 的结果较短,常见于一些旧系统或简单校验场景。

不过需要注意,MD5 已经不适合用于真正安全要求较高的密码存储场景。本项目使用 MD5 主要是为了演示摘要生成效果,不是让你把它当安全锁。把老锁装银行金库上,多少有点对犯罪分子太友好。


5. 输入校验

生成摘要前,页面会判断每个输入框是否为空:

if (course === '') {
  this.resultText = '课程名称不能为空';
  this.resultColor = '#E84026';
  return;
}

这样可以避免空内容参与摘要生成。

如果课程名称、学号、日期或口令为空,页面会给出对应提示。


6. 填充示例和清空功能

为了方便测试,页面提供了“填充示例”和“清空”按钮。

填充示例:

fillSample(): void {
  this.courseName = 'OpenHarmony应用开发';
  this.studentId = '20260001';
  this.checkDate = '2026-05-11';
  this.secretCode = 'study-hard';
}

清空内容:

clearAll(): void {
  this.courseName = '';
  this.studentId = '';
  this.checkDate = '';
  this.secretCode = '';
}

这样测试时不需要反复手动输入内容,毕竟重复打字这种事,实在不像文明社会该有的生产力。


十、运行效果说明

完成代码后,点击 DevEco Studio 中的运行按钮,将应用运行到 OpenHarmony 模拟器中。

运行成功后,页面顶部显示:

打卡摘要生成器

页面会自动填充一组示例数据,并生成对应的 SHA-256 和 MD5 摘要结果。

修改任意输入内容后,再次点击“生成摘要”,可以看到摘要结果发生变化。

点击“清空”按钮后,页面会清除所有输入内容和摘要结果。


十一、开发中遇到的问题

1. 找不到 @ohos/crypto-js 模块

如果代码中出现找不到模块的问题,可以先检查是否已经执行安装命令:

ohpm install @ohos/crypto-js

同时检查项目中是否存在:

oh_modules
oh-package-lock.json5

如果依赖没有正确安装,可以重新执行安装命令。


2. import 导入报错

如果下面代码导入时报错:

import { CryptoJS } from '@ohos/crypto-js';

可以尝试使用另一种导入方式:

import CryptoJS from '@ohos/crypto-js';

如果仍然报错,可以先确认 oh-package.json5 中是否已经正确写入依赖,并尝试重新同步项目或重启 DevEco Studio。

DevEco Studio 偶尔需要重启才肯承认依赖存在,像极了某些人类早上需要咖啡才能承认世界存在。


3. 摘要结果每次不一样

如果输入内容完全一样,摘要结果应该保持一致。

如果每次结果不一样,需要检查:

  • 课程名称是否有空格;
  • 学号是否输入一致;
  • 日期是否一致;
  • 自定义口令是否一致;
  • 拼接格式是否变化。

本项目中使用了 trim() 去掉前后空格,可以减少因为多输入空格导致摘要变化的问题。


4. 摘要算法是不是加密算法

不是。

摘要算法是单向处理,一般不能从摘要结果还原原始文本。它适合用于校验内容是否一致,而不是用于保存可以解密的内容。

如果需要真正的加密和解密,应该使用 AES、DES 等对称加密算法,并合理管理密钥。


5. SHA-256 和 MD5 有什么区别

简单来说:

算法 特点
MD5 结果短,速度快,但安全性较弱
SHA-256 结果更长,安全性更强,更适合现代场景

本项目同时展示两个结果,主要是为了让开发者更直观地看到不同摘要算法生成结果的差异。


十二、总结

本篇完成了一个基于 @ohos/crypto-js 的学习打卡口令摘要生成器。项目通过用户输入课程名称、学号、打卡日期和自定义口令,拼接成原始文本,再使用 SHA-256 和 MD5 生成摘要结果,并通过 ArkUI 展示在页面中。

通过本次实践,我主要完成了以下内容:

  • 安装并使用 @ohos/crypto-js 三方库;
  • 在 ArkTS 页面中引入 CryptoJS
  • 使用 TextInput 接收打卡信息;
  • 拼接原始摘要文本;
  • 使用 CryptoJS.SHA256() 生成 SHA-256 摘要;
  • 使用 CryptoJS.MD5() 生成 MD5 摘要;
  • 使用 ArkUI 构建卡片式工具页面;
  • 实现填充示例、清空内容和状态提示;
  • 在模拟器中完成运行验证。

虽然这个项目只是一个基础摘要生成页面,但它已经包含了工具类应用中常见的输入、校验、处理、结果展示和异常提示流程。

后续可以继续扩展为一个更完整的安全工具页面,例如:

  • 添加 HMAC-SHA256 签名;
  • 添加 AES 加密解密;
  • 添加摘要结果复制功能;
  • 添加随机盐值生成;
  • 添加历史记录保存;
  • 添加接口签名模拟;
  • 添加文件摘要计算;
  • 添加打卡二维码生成。

整体来看,@ohos/crypto-js 可以帮助开发者更方便地在 OpenHarmony 项目中实现摘要、加密等相关功能。通过这个项目,可以更清楚地理解 OpenHarmony 中三方库接入、摘要算法调用和 ArkUI 页面展示之间的关系。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐