1# 使用Node-API接口进行函数创建和调用
2
3## 简介
4
5函数调用允许开发者从Node-API模块中调用ArkTS函数,并传递参数进行调用,或者直接在Node-API模块中创建一个ArkTS方法。
6
7## 基本概念
8
9函数是一种非常重要的编程概念,可以执行特定的任务或操作、提高代码的可读性、把复杂任务简化、提高代码复用性以及支持代码的组织与管理。每个函数可以负责不同的功能,提供一种将代码模块化和组织结构化的方式,使其更易于理解、维护和重用。
10
11## 场景和功能介绍
12
13| 接口 | 描述 |
14| -------- | -------- |
15| napi_get_cb_info | 当需要从给定的callback info中获取有关调用的参数信息和this指针时,可使用此接口。 |
16| napi_call_function | 当需要在Node-API模块中对ArkTS侧函数进行调用时,可使用此接口。 |
17| napi_create_function | 当需要将C/C++函数创建一个ArkTS函数时,可以使用此接口。 |
18
19## 使用示例
20
21Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](use-napi-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。napi_create_function方法除外,具体使用见示例。
22
23## napi_get_cb_info
24
25获取有关函数调用的详细信息。
26
27cpp部分代码
28
29```cpp
30#include "napi/native_api.h"
31// 获取ArkTS侧入参的的参数信息
32static napi_value GetCbArgs(napi_env env, napi_callback_info info)
33{
34    size_t argc = 1;
35    napi_value args[1] = {nullptr};
36    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
37    return args[0];
38}
39// 获取ArkTS侧入参的参数个数
40static napi_value GetCbArgQuantity(napi_env env, napi_callback_info info)
41{
42    size_t argc = 0;
43    napi_value result = nullptr;
44    napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
45    napi_create_int32(env, argc, &result);
46    return result;
47}
48// 获取ArkTS侧this参数
49static napi_value GetCbContext(napi_env env, napi_callback_info info)
50{
51    napi_value thisArg = nullptr;
52    napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr);
53    return thisArg;
54}
55```
56
57接口声明
58
59```ts
60// index.d.ts
61export const getCbArgs: <T>(arg: T) => T;
62// getCbArgQuantity的入参由用户自定义,在此用例中,我们用两个入参,一个是string,一个是number
63export const getCbArgQuantity: (str: string, num: number) => number;
64export const getCbContext: () => Object;
65```
66
67ArkTS 侧示例代码
68
69```ts
70import hilog from '@ohos.hilog'
71import testNapi from 'libentry.so'
72function summation(arr: Array<number>) {
73  let sum: number = 0;
74  for (let i = 0; i < arr.length; i++) {
75    sum += arr[i];
76  }
77  return sum;
78}
79const str = 'message';
80const arr = [0, 1, 2, 3, 4, 5];
81const num = 526;
82class Student {
83  name: string;
84  age: number;
85  score: number;
86  constructor(name: string, age: number, score: number) {
87    this.name = name;
88    this.age = age;
89    this.score = score;
90  }
91}
92let student = new Student('Alice', 18, 100);
93// 获取参数
94hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get string arg:%{public}s', testNapi.getCbArgs(str));
95hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get array arg:%{public}s ', testNapi.getCbArgs(arr).toString());
96hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get num arg:%{public}d ', testNapi.getCbArgs(num));
97hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get undefined arg:%{public}s ', testNapi.getCbArgs(undefined));
98hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get object arg:%{public}s ', JSON.stringify(testNapi.getCbArgs(student)));
99hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get function arg:%{public}d ', testNapi.getCbArgs(summation(arr)));
100// 获取参数个数
101hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get arg quantity:%{public}d ', testNapi.getCbArgQuantity(str, num));
102// 获取上下文
103hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_cb_info get thisArg:%{public}s ', testNapi.getCbContext().toString());
104```
105
106## napi_call_function
107
108在C/C++侧对ArkTS函数进行调用。
109注意事项:napi_call_function传入的argv的长度必须大于等于argc声明的数量,且被初始化成nullptr。
110
111cpp部分代码
112
113```cpp
114#include "napi/native_api.h"
115
116static napi_value CallFunction(napi_env env, napi_callback_info info)
117{
118    size_t argc = 1;
119    napi_value argv[1] = {nullptr};
120    // 获取ArkTS侧入参
121    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
122    // 获取全局对象,这里用global是因为napi_call_function的第二个参数是JS函数的this入参。
123    napi_value global = nullptr;
124    napi_get_global(env, &global);
125    // 调用ArkTS方法
126    napi_value result = nullptr;
127    // 调用napi_call_function时传入的argv的长度必须大于等于argc声明的数量,且被初始化成nullptr
128    napi_call_function(env, global, argv[0], argc, argv, &result);
129    return result;
130}
131
132static napi_value ObjCallFunction(napi_env env, napi_callback_info info)
133{
134    // 获取ArkTS侧传递的两个参数
135    size_t argc = 2;
136    napi_value argv[2] = {nullptr};
137    // 获取ArkTS侧入参
138    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
139    // 调用ArkTS方法
140    napi_value result = nullptr;
141    // 调用napi_call_function时传入的argv的长度必须大于等于argc声明的数量,且被初始化成nullptr
142    napi_call_function(env, argv[0], argv[1], argc, argv, &result);
143    return result;
144}
145```
146
147接口声明
148
149```ts
150// index.d.ts
151export const callFunction: (func: Function) => number;
152export const objCallFunction: (obj: Object, func: Function) => number;
153```
154
155ArkTS 侧示例代码
156
157```ts
158import hilog from '@ohos.hilog'
159import testNapi from 'libentry.so'
160
161function returnNumber() {
162  return 10;
163}
164class Person {
165  age(): number {
166    return 11;
167  }
168}
169const person = new Person();
170hilog.info(0x0000, 'testTag', 'Test Node-API call_function:%{public}d', testNapi.callFunction(returnNumber));
171hilog.info(0x0000, 'testTag', 'Test Node-API call_function:%{public}d', testNapi.objCallFunction(person,person.age));
172```
173
174## napi_create_function
175
176将一个C/C++函数包装为可在ArkTS中调用的函数,并返回一个表示该函数的napi_value。
177
178cpp部分代码
179
180```cpp
181#include "napi/native_api.h"
182
183static napi_value CalculateArea(napi_env env, napi_callback_info info)
184{
185    // 获取ArkTS侧传递的两个参数
186    size_t argc = 2;
187    napi_value args[2] = {nullptr};
188    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
189    double width = 0;
190    napi_get_value_double(env, args[0], &width);
191    double height = 0;
192    napi_get_value_double(env, args[1], &height);
193    napi_value area = nullptr;
194    napi_create_double(env, width * height, &area);
195    return area;
196}
197
198EXTERN_C_START
199static napi_value Init(napi_env env, napi_value exports) {
200    napi_value fn = nullptr;
201    napi_create_function(env, nullptr, 0, CalculateArea, nullptr, &fn);
202    napi_set_named_property(env, exports, "calculateArea", fn);
203    return exports;
204}
205EXTERN_C_END
206```
207
208接口声明
209
210```ts
211// index.d.ts
212export const calculateArea: (width: number, height: number) => number;
213```
214
215ArkTS 侧示例代码
216
217```ts
218import hilog from '@ohos.hilog'
219import testNapi from 'libentry.so'
220
221hilog.info(0x0000, 'testTag', 'Test Node-API create_function:%{public}d ', testNapi.calculateArea(1.2, 4));
222```
223
224以上代码如果要在native cpp中打印日志,需在CMakeLists.txt文件中添加以下配置信息(并添加头文件:#include "hilog/log.h"):
225
226```text
227// CMakeLists.txt
228add_definitions( "-DLOG_DOMAIN=0xd0d0" )
229add_definitions( "-DLOG_TAG=\"testTag\"" )
230target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
231```
232