# 16.4:NAPI方法扩展
在前 3 小结笔者简单介绍了 NAPI 工程并对生成的源码进行了简单介绍,本节笔者在前 3 小节的基础上对 NAPI 工程做个扩展,再额外添加一个计算 MD5 的方法 md5()
。
# 16.4.1:声明md5方法
在 index.d.ts 文件中声明一个 md5()
方法,该方法接收一个 string 参数,返回类型也是 string 类型,表示经过 MD5 计算后的值,样例代码如下所示:
export const add: (a: number, b: number) => number;
// 声明 md5 方法
export const md5: (value: string) => string;
2
3
4
# 16.4.2:映射C++方法
在前 3 节的介绍中我们知道,JS 端声明的方法由 C++ 端实现时需要把两端的方法做个映射,因此先在 hello.cpp 的 Init()
方法内设置 md5()
方法为 C++ 的 Md5()
方法,样例代码如下所示:
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
// 设置JS的md5()方法的C++实现为Md5()方法,其它参数默认即可
{ "md5", nullptr, Md5, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
2
3
4
5
6
7
8
9
10
11
# 16.4.3:实现C++代码
在 Init()
方法中配置了 C++ 的 Md5()
方法后,需要实现 Md5()
方法,样例代码如下所示:
static napi_value Md5(napi_env env, napi_callback_info info) {
// 1、从info中取出JS传递过来的参数放入args
size_t argc = 1;
napi_value args[1] = { nullptr };
if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
napi_throw_error(env, "-1000", "napi_get_cb_info error");
return nullptr;
}
// 2、获取参数的类型
napi_valuetype stringType;
if (napi_ok != napi_typeof(env, args[0], &stringType)) {
napi_throw_error(env, "-1001", "napi_typeof error");
return nullptr;
}
// 3、如果参数为null,则抛异常
if (napi_null == stringType) {
napi_throw_error(env, "-1002", "the param can't be null");
return nullptr;
}
// 4、获取传递的string长度
size_t length = 0;
if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
napi_throw_error(env, "-1003", "napi_get_value_string_utf8 error");
return nullptr;
}
// 5、如果传递的是"",则抛异常
if (length == 0) {
napi_throw_error(env, "-1004", "the param length invalid");
return nullptr;
}
// 6、读取传递的string参数放入buffer中
char* buffer = new char[length + 1];
if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
delete[] buffer;
buffer = nullptr;
napi_throw_error(env, "-1005", "napi_get_value_string_utf8 error");
return nullptr;
}
// 7、模拟MD5加密操作,直接给传递进来的string后追加[NAPI]
std::string str = buffer;
str = str + "[NAPI]";
// 8、把C++数据转成napi_value
napi_value value = nullptr;
const char* md5 = str.c_str();
if (napi_ok != napi_create_string_utf8(env, md5, strlen(md5), &value)) {
delete[] buffer;
buffer = nullptr;
napi_throw_error(env, "-1006", "napi_create_string_utf8 error");
return nullptr;
}
// 9、资源清理
delete[] buffer;
buffer = nullptr;
// 返回 value
return value;
}
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
Md5()
方法的解释说明的很清楚:第 1 步从 napi_callback_info
中读取传递进来的参数放入 args
中;第 2 步读取传递的参数类型;第 3 步判断参数类型是否为 null
,如果为 null
则抛异常;第 4 步读取参数长度;第 5 步如果传递的参数为 ""
则抛异常;第 6 步根据参数长度把参数读取出来放入 buffer
里,第 7 布模拟 MD5 操作直接在参数末尾追加 [NAPI]
字符串,第 8 步把 C++ 类型转换成 napi_value
类型,第 9 布清理资源,第 10 步返回结果。
📢:读取 string 时先读取参数的长度,再读取内容。
# 16.4.4:测试C++方法
根据 Md5()
方法的实现,限制条件是不允许数据 null 和 "",如果输入则抛异常。因此可测试以下三种场景:正常参数,null 参数和 "" 参数,样例代码如下所示:
import testNapi from 'libentry.so'
@Entry @Component struct Index {
@State message: string = 'Hello,OpenHarmony'
build() {
Column({space: 10}) {
Text(this.message)
.fontSize(20)
Button("正常参数")
.onClick(() => {
this.message = testNapi.md5("Hello, OpenHarmony")
})
Button("null参数")
.onClick(() => {
this.message = testNapi.md5(null);
})
Button("\"\"参数")
.onClick(() => {
this.message = testNapi.md5("");
})
}
.padding(10)
.width('100%')
.height("100%")
}
}
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
点解 正常参数 按钮,样例运行结果如下所示:
点击 null参数 测试异常情况,异常日志如下:
02-28 23:50:56.176 2093-2093/com.example.oh_0400_napi E C03f00/ArkCompiler: [default] Call:1307 occur exception need return
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: [jsi_base_utils.cpp(ReportJsErrorEvent)-(0)] summaryBody:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Lifetime: 0.000000s
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Js-Engine: ark
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: page: pages/Index.js
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Error message: the param can't be null
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: SourceCode:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: this.message = testNapi.md5(null);
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: ^
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Stacktrace:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: at anonymous (/ets/pages/Index.ets:20:26)
2
3
4
5
6
7
8
9
10
11
# 16.4.5:小结
本节笔者在前 3 小节的基础上简单实现了 C++ 端的 md5()
方法并实现 JS 端调用,该 md5()
方法是一个模拟,目的是跑通 JS 到 C++的调用流程,下节笔者将要介绍如何引入三方库实现真正的 MD5 计算。