前言
阅读本文,你将解锁以下成就😎😎😎
- 鸿蒙应用开发
- 发布鸿蒙
ohpm
包 - 了解
ArkTS
、ArkUI
语法
如果文章对你有帮助的话,记得一键三连哟。有问题和疑惑的话也可以在评论区留言。我会第一时间回复大家,如果觉得我的文章哪里有知识点错误的话,也恳请能够告知,把错的东西理解成对的,无论在什么行业,都是致命的。
依赖
项目基于OpenHarmony
、api10
、DevEco Studio 4.0 Beta2
项目仓库
编辑器
安装
developer.huawei.com/consumer/cn...
汉化
进入插件中心,在已安装里面搜索 chinese
,勾选并确认,重启后汉化完成
SDK下载
下载OpenHarmony
、ArkUI
相关SDK
安装ohpm
ohpm
相当于鸿蒙版本的npm
,能管理依赖, 同时需要安装node
工具,后面需要用到它提交包和安装依赖。
配置环境变量
以mac
为例,其他系统自行搜索
bash
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
,导入自己写的公共方法
ts
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
导出方法
ts
import {generateTotp} from "./src/main/ets/totp"
export default generateTotp;
export { generateTotp };
修改包信息
修改包信息为如下格式,有些字段是必填,如果字段存在问题,提交到ohpm
的时候提示错误信息
json
{
"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
命令以同步包
json
{
"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
,引入包并使用
ts
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-keypath
(mac
一般放在~/.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.md
、README.md
、LICENSE
等必要文件,且不能为空。
bash
ohpm publish /testProject/totp/build/default/outputs/default/totp.har
遇到的问题
publish
时,提示artifactType
相关错误,修改build-profile.json5
,增加以下字段
json
"buildOption": {
"artifactType": "original"
},
审核状态
致谢
在鸿蒙应用开发-我的第一个三方库 - 掘金的文章中学习到了不少内容