前言

浏览本文,你将解锁以下成就

  • 鸿蒙利用开发
  • 公布鸿蒙ohpm
  • 理解ArkTSArkUI语法

如果文章对你有帮忙的话,记得一键三连哟。有问题和纳闷的话也能够在评论区留言。我会第一工夫回复大家,如果感觉我的文章哪里有知识点谬误的话,也恳请可能告知,把错的货色了解成对的,无论在什么行业,都是致命的。

依赖

我的项目基于OpenHarmonyapi10DevEco Studio 4.0 Beta2

我的项目仓库

https://github.com/taosiqi/oh-mfa

编辑器

装置

https://developer.huawei.com/consumer/cn/forum/topic/02071242...

汉化

进入插件核心,在已装置外面搜寻 chinese,勾选并确认,重启后汉化实现

SDK下载

下载OpenHarmonyArkUI 相干SDK

装置ohpm

ohpm相当于鸿蒙版本的npm,能治理依赖, 同时须要装置node工具,前面须要用到它提交包和装置依赖。

配置环境变量

mac为例,其余零碎自行搜寻

OHPM_HOME=/Users/taosiqi/Library/Huawei/ohpm  # 替换为下图的门路export PATH=${PATH}:${OHPM_HOME}/bin

项目管理

导入工程

新建我的项目临时不能应用api10,须要导入实例工程(不确定新建我的项目批改配置文件为api10能不能应用)


查看配置文件,是用的10版本

批改我的项目信息

依据本人的要求,批改包名、Icon、利用名称等

编译我的项目

首次编译我的项目时,依据控制台提醒,生成证书,抉择真机运行,模拟器临时不反对api10我的项目


真机运行

新增模块(可公布为ohpm包)

在我的项目根目录,新增模块,新增 Static Library,我这里包名叫totp,前面以这个为例


我的项目开发

删除无用目录

删除包上面的/totp/src/main/ets/components目录,这个我的项目是抽离通用办法

编写包代码

/totp/src/main/ets/下新建 totp.ets,导入本人写的公共办法

import { CryptoJS } from '@ohos/crypto-js'type HashAlgorithm = 'SHA1' | 'SHA224' | 'SHA256' | 'SHA384' | 'SHA512' | 'SHA3';interface TokenOptions {  period?: number;  digits?: number;  timestamp?: number;  algorithm?: HashAlgorithm | undefined;}/** * 生成验证码 * @param key * @param options * @returns */export function generateTotp(key: string, options?: TokenOptions): string {  try {    let epoch: number, time: string, mac: string, offset: number, otp: string;    options = options || {};    options.period = options.period || 30;    options.digits = options.digits || 6;    options.timestamp = options.timestamp || Date.now();    options.algorithm = options.algorithm || "SHA1"    key = base32hex(key);    epoch = Math.floor(options.timestamp / 1000.0);    time = leftPad(dec2hex(Math.floor(epoch / options.period)), 16, "0");    // 应用CryptoJS计算HMAC,动静抉择哈希算法    const keyHex = CryptoJS.enc.Hex.parse(key);    const timeHex = CryptoJS.enc.Hex.parse(time);    mac = hmacDigest(options.algorithm, timeHex, keyHex);    offset = hex2dec(mac.substring(mac.length - 1));    otp = ((hex2dec(mac.substring(offset * 2, offset * 2 + 8)) & hex2dec("7fffffff")) + "").substring(0);    otp = otp.substring(otp.length - options.digits);    return otp;  } catch (e) {    return ''  }}/** * 动静抉择算法 * @param algorithm * @param message * @param key * @returns */function hmacDigest(algorithm: HashAlgorithm, message: string, key: string): string {  let mac  switch (algorithm) {    case 'SHA224':      mac = CryptoJS.HmacSHA224(message, key);    case 'SHA256':      mac = CryptoJS.HmacSHA256(message, key);    case 'SHA384':      mac = CryptoJS.HmacSHA384(message, key);    case 'SHA512':      mac = CryptoJS.HmacSHA512(message, key);    case 'SHA3':      mac = CryptoJS.HmacSHA3(message, key);    case 'SHA1':    default:      mac = CryptoJS.HmacSHA1(message, key)  }  return mac.toString(CryptoJS.enc.Hex);}/** * 将十六进制字符串转换为对应的十进制数值 * @param s * @returns */function hex2dec(s: string): number {  return parseInt(s, 16);}/** * 将一个十进制数转换为对应的十六进制 * @param s * @returns */function dec2hex(s: number): string {  return (s < 15.5 ? "0" : "") + Math.round(s).toString(16);}/** * base32转hex * @param base32 * @returns */function base32hex(base32: string): string {  const base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";  let bits = "";  let hex = "";  base32 = base32.replace(/=+$/, "");  for (let i = 0; i < base32.length; i++) {    const val = base32chars.indexOf(base32.charAt(i).toUpperCase());    if (val === -1) throw new Error("Invalid base32 character in key");    bits += val.toString(2).padStart(5, '0');  }  for (let i = 0; i + 8 <= bits.length; i += 8) {    const chunk = bits.slice(i, i + 8);    hex += parseInt(chunk, 2).toString(16).padStart(2, '0');  }  return hex;}/** * 左侧填充字符串,确保填充后的字符串长度达到指定的长度 * @param str * @param len * @param pad * @returns */function leftPad(str: string, len: number, pad: string): string {  if (len + 1 >= str.length) {    str = Array(len + 1 - str.length).join(pad) + str;  }  return str;}

安装包级别依赖

cd totp,装置依赖 ohpm install @ohos/crypto-js

导出办法

totp包根目录Index.ets导出办法

import {generateTotp} from "./src/main/ets/totp"export default generateTotp;export { generateTotp };

批改包信息

批改包信息为如下格局,有些字段是必填,如果字段存在问题,提交到ohpm的时候提醒错误信息

{  "name": "totp",  "types": "",  "keywords": [    "HarmonyOS",    "totp",    "generator",    "auth",    "authentication",    "google authenticator",    "oath",    "2-factor",    "two-factor",    "mfa"  ],  "author": "taosiqi",  "description": "从密钥生成TOTP验证码 Generate TOTP tokens from key ",  "main": "Index.ets",  "repository": "https://github.com/taosiqi/oh-mfa.git",  "type": "module",  "version": "0.0.1",  "tags": [    "Tools",    "Security"  ],  "license": "MIT",  "devDependencies": {},  "dependencies": {    "@ohos/crypto-js": "^2.0.3"  }}

构建包

构建totp

输入的包目录

引入本地包

/entry/oh-package.json5应用file:xxx门路,引入本地包,点击右上角Sync Now或关上终端执行 ohpm install命令以同步包

{  "license": "",  "devDependencies": {},  "author": "",  "name": "entry",  "description": "Please describe the basic information.",  "main": "",  "version": "1.0.0",  "dependencies": {    "totp": "file:/Users/taosiqi/DevEcoStudioProjects/testProject/totp/build/default/outputs/default/totp.har"  }}

调试代码

批改entry/src/main/ets/pages/Index.ets,引入包并应用

import { generateTotp } from 'totp'@Entry  @Component  struct Index {    @State totpKey: string = '5F7XTR3O5ANHF4UI'    @State genTotpKey: string = ''    @State second: number = 30    @State focusableAccount: boolean = false;    intervalID: number    countdown() {      this.intervalID = setInterval(() => {        this.second= 30 - (new Date().getSeconds() % 30)        if(this.second===30){          this.genTotpKey=generateTotp(this.totpKey)        }      }, 1000);    };    async onPageShow(){      this.genTotpKey=generateTotp(this.totpKey)      this.countdown()    }    build() {      Column({ space: 35 }) {        Text(`倒计时${this.second}s`).fontSize(28)        Text(this.genTotpKey).fontSize(40)        TextInput({ text: this.totpKey, placeholder: 'input your word...' }).onChange((value)=>{          this.totpKey=value        }).width(300).defaultFocus(false).focusable(this.focusableAccount).onClick(()=>{          // 默认会聚焦,defaultFocus有效,不晓得是不是版本问题          if(!this.focusableAccount){            this.focusableAccount = true;          }        });        Button('刷新验证码').onClick(()=>{          this.genTotpKey=generateTotp(this.totpKey)        })        Text('举荐应用《MFA二次验证码》微信小程序版本').fontSize(16)        Image('https://static-1253419794.cos.ap-nanjing.myqcloud.com/img/code.jpg').width(200).height(200)      }.justifyContent(FlexAlign.Center).width('100%').height('100%')    }  }

运行成果

运行查看实际效果

打包公布

打包example利用

entry目录下构建hap,打包完的代码就能提供给人装置

公布筹备工作

  • 注册鸿蒙三方库的账号,注册地址 ohpm.openharmony.cn/#/cn/home
  • 生成公私钥:执行ssh-keygen -m PEM -t RSA -b 4096 -f your-keypathmac个别放在~/.ssh目录)
  • ohpm包管理器只反对加密密钥认证,请在生成公私钥时输出明码
  • 配置私钥门路:执行ohpm config set key_path your-keypath(配置间接批改 ~/.ohpm/.ohpmrc也能够)
  • 配置登录用户公布码,在命令行执行:ohpm config set publish_id your-publishId
  • 在集体核心的ohpm公钥治理模块中,增加公钥,并将公钥文件的内容(your-keypath.pub)粘贴到公钥输入框中

公布totp包到ohpm

须要在totp模块根目录增加CHANGELOG.mdREADME.md LICENSE 等必要文件,且不能为空。

ohpm publish /testProject/totp/build/default/outputs/default/totp.har

遇到的问题

  1. publish时,提醒artifactType相干谬误,批改build-profile.json5,减少以下字段
"buildOption": {  "artifactType": "original"},

审核状态

致谢

在鸿蒙利用开发-我的第一个三方库 - 掘金的文章中学习到了不少内容

援用

首发于语雀文档@is_tao