使用Node-API接口进行函数创建和调用
=====================

#### 简介

函数调用允许开发者从Node-API模块中调用ArkTS函数并传递参数，或在Node-API模块中创建ArkTS函数。

#### 基本概念

函数是一种非常重要的编程概念，可以执行特定的任务或操作、提高代码的可读性、把复杂任务简化、提高代码复用性以及支持代码的组织与管理。每个函数可以负责不同的功能，提供一种将代码模块化和组织结构化的方式，使其更易于理解、维护和重用。

#### 场景和功能介绍

| 接口 | 描述 |
| :-- | :-- |
| napi\_get\_cb\_info | 当需要从给定的callback info中获取有关调用的参数信息和this指针时，可使用此接口。 |
| napi\_call\_function | 当需要在Node-API模块中对ArkTS侧函数进行调用时，可使用此接口。 |
| napi\_create\_function | 当需要将C/C++函数创建为ArkTS函数时，可以使用此接口。 |

#### 使用示例

Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-process)，本文仅对接口对应C++及ArkTS相关代码进行展示。

#### napi\_get\_cb\_info

获取有关函数调用的详细信息。

cpp部分代码

#include "napi/native\_api.h"

// napi\_get\_cb\_info
// 获取ArkTS侧入参的参数信息
static napi\_value GetCbArgs(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    return args\[0\];
}

// 获取ArkTS侧入参的参数个数
static napi\_value GetCbArgQuantity(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 0;
    napi\_value result = nullptr;
    napi\_get\_cb\_info(env, info, &argc, nullptr, nullptr, nullptr);
    napi\_create\_int32(env, argc, &result);
    return result;
}

// 获取ArkTS侧this参数
static napi\_value GetCbContext(napi\_env env, napi\_callback\_info info)
{
    napi\_value thisArg = nullptr;
    napi\_get\_cb\_info(env, info, nullptr, nullptr, &thisArg, nullptr);
    return thisArg;
}

接口声明

export const getCbArgs: <T>(arg: T) => T; // napi\_get\_cb\_info

// getCbArgQuantity的入参由用户自定义，在此用例中，我们用两个入参，一个是string，一个是number
export const getCbArgQuantity: (str: string, num: number) => number;

export const getCbContext: () => Object;

ArkTS 侧示例代码

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

function summation(arr: Array<number>) {
  let sum: number = 0;
  for (let i = 0; i < arr.length; i++) {
    sum += arr\[i\];
  }
  return sum;
}

const str = 'message';
const arr = \[0, 1, 2, 3, 4, 5\];
const num = 526;

class Student {
  name: string;
  age: number;
  score: number;

  constructor(name: string, age: number, score: number) {
    this.name = name;
    this.age = age;
    this.score = score;
  }
}

// napi\_get\_cb\_info
let student = new Student('Alice', 18, 100);
// 获取参数
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get string arg:%{public}s',
  testNapi.getCbArgs(str));
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get array arg:%{public}s ',
  testNapi.getCbArgs(arr).toString());
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get num arg:%{public}d ',
  testNapi.getCbArgs(num));
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get undefined arg:%{public}s ',
  testNapi.getCbArgs(undefined));
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get object arg:%{public}s ',
  JSON.stringify(testNapi.getCbArgs(student)));
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get function arg:%{public}d ',
  testNapi.getCbArgs(summation(arr)));
// 获取参数个数
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get arg quantity:%{public}d ',
  testNapi.getCbArgQuantity(str, num));
// 获取上下文
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_cb\_info get thisArg:%{public}s ',
  testNapi.getCbContext().toString());

#### napi\_call\_function

在C/C++侧对ArkTS函数进行调用。

注意事项：napi\_call\_function传入的argv的长度必须大于等于argc声明的数量，并且每个元素都应初始化为nullptr。

cpp部分代码

// napi\_call\_function
static napi\_value CallFunction(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value argv\[1\] = {nullptr};
    // 获取ArkTS侧入参
    napi\_get\_cb\_info(env, info, &argc, argv, nullptr, nullptr);
    // 获取全局对象，这里用global是因为napi\_call\_function的第二个参数是JS函数的this入参。
    napi\_value global = nullptr;
    napi\_get\_global(env, &global);
    // 调用ArkTS方法
    napi\_value result = nullptr;
    // 调用napi\_call\_function时传入的argv的长度必须大于等于argc声明的数量，且被初始化成nullptr
    napi\_call\_function(env, global, argv\[0\], argc, argv, &result);
    return result;
}

static napi\_value ObjCallFunction(napi\_env env, napi\_callback\_info info)
{
    // 获取ArkTS侧传递的两个参数
    size\_t argc = 2;
    napi\_value argv\[2\] = {nullptr};
    // 获取ArkTS侧入参
    napi\_get\_cb\_info(env, info, &argc, argv, nullptr, nullptr);
    // 调用ArkTS方法
    napi\_value result = nullptr;
    // 调用napi\_call\_function时传入的argv的长度必须大于等于argc声明的数量，且被初始化成nullptr
    napi\_call\_function(env, argv\[0\], argv\[1\], argc, argv, &result);
    return result;
}

接口声明

export const callFunction: (func: Function) => number; // napi\_call\_function

export const objCallFunction: (obj: Object, func: Function) => number;

ArkTS 侧示例代码

function returnNumber() {
  return 10;
}

class Person {
  age(): number {
    return 11;
  }
}

// napi\_call\_function
const person = new Person();
hilog.info(0x0000, 'testTag', 'Test Node-API call\_function:%{public}d',
  testNapi.callFunction(returnNumber));
hilog.info(0x0000, 'testTag', 'Test Node-API call\_function:%{public}d',
  testNapi.objCallFunction(person, person.age));

#### napi\_create\_function

将一个C/C++函数包装为可在ArkTS中调用的函数，并返回一个表示该函数的napi\_value。

cpp部分代码

// napi\_create\_function
static napi\_value CalculateArea(napi\_env env, napi\_callback\_info info)
{
    // 获取ArkTS侧传递的两个参数
    size\_t argc = 2;
    napi\_value args\[2\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    double width = 0;
    napi\_get\_value\_double(env, args\[0\], &width);
    double height = 0;
    napi\_get\_value\_double(env, args\[1\], &height);
    napi\_value area = nullptr;
    napi\_create\_double(env, width \* height, &area);
    return area;
}

接口声明

export const calculateArea: (width: number, height: number) => number; // napi\_create\_function

ArkTS 侧示例代码

// napi\_create\_function
hilog.info(0x0000, 'testTag', 'Test Node-API create\_function:%{public}d ',
  testNapi.calculateArea(1.2, 4));

以上代码如果要在native cpp中打印日志，需在CMakeLists.txt文件中添加以下配置信息（并添加头文件：#include "hilog/log.h"）：

// CMakeLists.txt
add\_definitions( "-DLOG\_DOMAIN=0xd0d0" )
add\_definitions( "-DLOG\_TAG=\\"testTag\\"" )
target\_link\_libraries(entry PUBLIC libace\_napi.z.so libhilog\_ndk.z.so)