鸿蒙-MD5摘要(ArkTS)

SDK 版本:HarmonyOS NEXT Developer Beta2 SDK (5.0.0.31)
DevEco-Studio 版本:DevEco Studio NEXT Developer Beta2 (5.0.3.502)
工程机版本:ALN-AL00 NEXT.0.0.31

简介

MD5 算法常常被用来验证网络文件传输的完整性,防止文件被人篡改。MD5 全称是报文摘要算法(Message-Digest Algorithm 5),此算法对任意长度的信息逐位进行计算,产生一个二进制长度为 128 位(十六进制长度就是 32 位)的“指纹”(或称“报文摘要”),不同的文件产生相同的报文摘要的可能性是非常非常之小的。

Linux 下 md5sum 用法 (查看文件或字符串的 md5 值)

md5sum 命令采用 MD5 报文摘要算法(128 位)计算和检查文件的校验和。一般来说,安装了 Linux 后,就会有 md5sum 这个工具,直接在命令行终端直接运行。

windows 下如果安装了 git-bash 也可以在所在的文件夹下,右击,选择[Git Bash Here],也可以直接使用 md5sum 命令。

MD5 ArkTS 实现代码

MD5Util.ets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
* Copyright (c) 2024. Dench.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { cryptoFramework } from "@kit.CryptoArchitectureKit";
import { buffer } from "@kit.ArkTS";
import { hash } from "@kit.CoreFileKit";
import { systemDateTime } from "@kit.BasicServicesKit";

/**
* 计算字符串Md5
*/
export async function md5(messageText: string): Promise<string> {
const md = cryptoFramework.createMd("MD5");
await md.update({
data: new Uint8Array(buffer.from(messageText, "utf-8").buffer),
});
const mdOutput = await md.digest();
console.info("md mdOutput: " + mdOutput.data);
let mdLen = md.getMdLength();
console.info("md mdLen: " + mdLen);
const result = buffer.from(mdOutput.data.buffer).toString("hex");
console.info("md result: " + result);
return result;
}

// 文件Md5, 哈希计算采用的算法。可选 "md5"、"sha1" 或 "sha256"。建议采用安全强度更高的 "sha256", 此处使用"md5"
export async function fileMd5(filePath: string): Promise<string> {
try {
const t = systemDateTime.getTime();
const result = await hash.hash(filePath, "md5");
console.info("fileMd5: result=" + result);
console.info(`fileMd5: duration=${systemDateTime.getTime() - t}`);
return result;
} catch (err) {
console.error(`fileMd5: ${JSON.stringify(err)}`);
return "";
}
}

// 文件MD5,大文件读写效率低,有性能瓶颈,采用上面的文件Hash算法
// export async function fileMd5(path: string, algName: string = "MD5"): Promise<string> {
// console.info("fileMd5: path=" + path)
// let md = cryptoFramework.createMd(algName);
// try {
// const t = systemDateTime.getTime();
// let file = await fs.open(path, fs.OpenMode.READ_ONLY);
// let arrayBuffer = new ArrayBuffer(4096);
// let offset = 0;
// let readOptions: ReadOptions = {
// offset: offset,
// length: 4096
// };
// let len = await fs.read(file.fd, arrayBuffer, readOptions);
// while (len > 0) {
// // console.info("md read file len: " + len);
// const bf = buffer.from(arrayBuffer).subarray(0, len);
// // console.info("md bf: " + bf.buffer.byteLength);
// const uint8 = new Uint8Array(bf.buffer);
// // console.info("md uint8: " + uint8.byteLength);
// await md.update({ data: uint8 });
// offset += len;
// readOptions.offset = offset;
// len = await fs.read(file.fd, arrayBuffer, readOptions);
// }
// try {
// fs.close(file);
// } catch (e) {
// console.info(JSON.stringify(e));
// }
// let mdOutput = await md.digest();
// // console.info("md mdOutput: " + mdOutput.data);
// let mdLen = md.getMdLength();
// // console.info("md mdLen: " + mdLen);
// const result = buffer.from(mdOutput.data.buffer).toString('hex');
// console.info("md succeed: " + result);
// console.info(`md duration=${systemDateTime.getTime() - t}`);
// return result;
// } catch (e) {
// console.error("md error: " + JSON.stringify(e));
// return ''
// }
// }

Reference

https://www.cnblogs.com/kevingrace/p/10201723.html
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-file-hash-V5

鸿蒙-Text组件使用自定义字体

DevEco Studio 版本:DevEco Studio NEXT Developer Preview2
HarmonyOS API 版本:4.1.0(11)

1 导入字体文件

将字体文件BebasNeue-Regular.ttf放在项目的resources/rawfile文件夹下,如下图:

20240604201941

2 注册自定义字体

需要在组件的 aboutToAppear() 方法中,使用font注册自定义字体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import font from '@ohos.font';

@Component
export struct CustomFontComponent {
aboutToAppear(): void {
font.registerFont({
familyName: 'BebasNeue',
familySrc: $rawfile('BebasNeue-Regular.ttf')
})
}

build() {
Column() {
Text('9999')
.fontSize(17)
.fontColor('#333333')
.fontFamily('BebasNeue')
.maxLines(1)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Regular)
.textOverflow({
overflow: TextOverflow.Ellipsis
})
.height('100%')
.width('100%');
}
}
}

3 使用已注册的字体

在Text组件中使用已注册的字体,设置fontFamily为已注册的familyName即可。

参考

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-font-V5

鸿蒙-下拉刷新控件PullToRefresh使用

DevEco Studio 版本:DevEco Studio NEXT Developer Preview2
HarmonyOS API 版本:4.1.0(11)
PullToRefresh 版本:"@ohos/pulltorefresh": "2.0.5"

下拉刷新控件 PullToRefresh 使用

  • 支持自定义 header,footer
  • 没有更多了布局

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { HomeVM } from '../vm/HomeVM';
import { PullToRefresh } from '@ohos/pulltorefresh';

@Component
export struct ListAreaComponent {
@State data?: ListDataWrapper[] | null = null
private vm: HomeVM = new HomeVM()
// 需绑定列表或宫格组件
private scroller: Scroller = new Scroller();

aboutToAppear(): void {
// request data.
this.vm.requestData().then((data: ListDataWrapper[]) => {
this.data = data;
})
}

build() {
PullToRefresh({
// 必传项,列表组件所绑定的数据
data: this.data,
// 必传项,需绑定传入主体布局内的列表或宫格组件
scroller: this.scroller,
// 必传项,自定义主体布局,内部有列表或宫格组件
customList: () => {
// 一个用@Builder修饰过的UI方法
this.getListView()
},
// 可选项,下拉刷新回调
onRefresh: () => {
return new Promise<string>((resolve) => {
this.vm.requestData().then((data: ListDataWrapper[]) => {
this.data = data
resolve('')
}).catch((error: Error) => {
resolve('')
});
});
},
// 可选项,上拉加载更多回调
onLoadMore: () => {
return new Promise<string>((resolve) => {
resolve('')
});
},
customLoad: commonNoMore,
customRefresh: commonLoading,
})
.width('100%')
.height('100%')
}

@Builder
getListView() {
List({ space: 12, scroller: this.scroller }) {
ForEach(this.data, (item: ListDataWrapper, index: number) => {
ListItem() {
// ...
};
}, (item: ListDataWrapper, index?: number) => index + JSON.stringify(item));
}
.width('100%')
.height('100%')
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.None)
}
}


@Builder
export function commonLoading(): void {
Stack() {
// Text(refreshText)
// .textAlign(TextAlign.Center)
// .fontColor( 0)
// .fontSize( 0)
Stack() {
Canvas(new CanvasRenderingContext2D(new RenderingContextSettings(true)))
.width('100%')
.height('100%')
.onReady(() => {
// this.initCanvas();
}) // .visibility(this.state == IS_PULL_DOWN_2 ? Visibility.Visible : Visibility.Hidden)
// .visibility(Visibility.Hidden)
LoadingProgress()
.color('#FF00A3FF')
.width(32)
.height(32)
}
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.clip(true)
}

@Builder
export function commonNoMore(): void {
Stack() {
Text('已经到底了~')
.textAlign(TextAlign.Center)
.fontColor('#FF85888F')
.fontSize(14)
}
.width('100%')
.height('100%')
.clip(true)
}

@Builder
export function commonEmpty(): void {
Stack()
.width('100%')
.height('100%')
}

注意,列表组件需要设置为无边缘效果:List().edgeEffect(EdgeEffect.None)

参考

https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fpulltorefresh

为git仓库设置独立的账户和邮箱

为 git 仓库设置独立的账户和邮箱

0x01 配置 Git 全局默认的账户和邮箱

1
2
3
4
5
6
## 全局默认的用户名和邮箱
$ git config --global user.name "aaa"
$ git config --global user.email "aaa@gmail.com"

## 避免每次git操作都需要输入用户名密码
$ git config --global credential.helper store

0x02 为 git 仓库设置独立的账户和邮箱

使用编辑器打开.git/config文件,直接在文件的最后添加以下信息:

1
2
3
[user]
name = bbb
email = bbb@gmail.com

解析<em></em>标签高亮显示

DevEco Studio 版本:DevEco Studio NEXT Developer Preview2
HarmonyOS API 版本:4.1.0(11)

解析标签高亮显示

由于跟后端约定,接口中对于返回的字符串中,使用标签的内容需要使用主题色高亮显示。比如 <em>权力</em>的<em>游戏</em> 第<em>七</em>季

注意:当前版本不支持标签嵌套。

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Text() {
buildHighLightSpan(item.title)
}
.fontSize(17)
.fontColor('#FF222222')
.fontWeight(600)
.textOverflow({
overflow: TextOverflow.Ellipsis
})
.width('100%')


/**
* 解析 <em> </em>标签高亮显示
*
* 注意:不支持嵌套
*
* @param highLightTitle 带标签的文本
*/
@Builder
function buildHighLightSpan(highLightTitle: string | undefined) {
if (highLightTitle == null || highLightTitle.indexOf('<em>') == -1 || highLightTitle.indexOf('</em>') == -1) {
Span(highLightTitle?.replace('<em>', '').replace('</em>', '')).fontColor('#FF222222')
} else {
ForEach(highLightTitle.split('</em>'), (attr: string) => {
ForEach(attr.split('<em>'), (item: string, index: number) => {
if (item != null || item != '') {
if (index == 0) {
Span(item).fontColor('#FF222222');
} else {
Span(item).fontColor('#FF00A3FF');
}
}
});
})
}
}

组件之间的数据同步,@State,@Prop,@Watch装饰器

DevEco Studio 版本:DevEco Studio NEXT Developer Preview2
HarmonyOS API 版本:4.1.0(11)

组件之间的数据同步,@State,@Prop,@Watch 装饰器

这里是一个使用的@State,@Prop,@Watch 装饰器做组件之间的数据同步的 demo。

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
struct SearchResultPage {
@State input: string = '';
@State searchWord: string = ''

aboutToAppear(): void {
this.syncSearchWord(this.input)
}

build() {
Column() {
SearchDramaResultList({ searchWord: this.searchWord }).layoutWeight(1)
}
.width('100%')
.height('100%')
}

syncSearchWord(keyword: string) {
if (keyword == '') return;
this.searchWord = keyword
}
}

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
export struct SearchDramaResultList {
@Prop @Watch('requestData') searchWord: string;
@State data?: SearchSeasonVo[] | null = null
private vm = new SearchVM()
// 需绑定列表或宫格组件
private scroller: Scroller = new Scroller();

aboutToAppear(): void {
// request data.
this.requestData()
}

requestData(propName: string) {
console.log("requestData: searchWord=", this.searchWord, ",propName=", propName);
// do data request with searchWord
}
}
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×