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

#### 简介

函数调用允许开发者从JSVM模块中调用JavaScript函数，并传参，或者直接在JSVM模块中创建一个JavaScript函数。

#### 基本概念

函数是一种重要的编程概念，用于执行特定任务，提升代码可读性与复用性，简化复杂操作，并实现代码的模块化和结构化，便于理解、维护和扩展。

#### 接口说明

| 接口 | 功能说明 |
| :-- | :-- |
| OH\_JSVM\_GetCbInfo | 从给定的callback info中获取有关调用的详细信息，如参数和this指针。 |
| OH\_JSVM\_CallFunction | 在C/C++侧调用JavaScript方法。 |
| OH\_JSVM\_IsFunction | 判断对象是否为函数对象。 |
| OH\_JSVM\_CreateFunction | 用于创建JavaScript函数,用于从JavaScript环境中调用C/C++代码中的函数, 需要设置到一个JavaScript对象中才可以进行调用。 |

#### 使用示例

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

#### \[h2\]OH\_JSVM function整合测试

cpp测试全量代码，入口为TEST\_FUNC

#include "napi/native\_api.h"
#include "hilog/log.h"
#include "ark\_runtime/jsvm.h"

#define LOG\_DOMAIN 0x3200
#define LOG\_TAG "APP"

#define CHECK\_RET(cond)                                                                                                \\
    if ((cond)) {                                                                                                      \\
        const JSVM\_ExtendedErrorInfo \*info;                                                                            \\
        OH\_JSVM\_GetLastErrorInfo(env, &info);                                                                          \\
        OH\_LOG\_ERROR(LOG\_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s",     \\
                     \_\_FILE\_\_, \_\_LINE\_\_, cond, info != nullptr ? info->errorMessage : "");                             \\
        return -1;                                                                                                     \\
    }

#define CHECK(cond)                                                                                                    \\
    if (!(cond)) {                                                                                                     \\
        OH\_LOG\_ERROR(LOG\_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d", \_\_FILE\_\_, \_\_LINE\_\_,      \\
                     cond);                                                                                            \\
        return -1;                                                                                                     \\
    }

JSVM\_Value NativeCreateFunctionTest(JSVM\_Env env, JSVM\_CallbackInfo info)
{
    void \*data;
    size\_t argc = 1;
    JSVM\_Value argv\[1\] = {nullptr};
    JSVM\_Value thisArg;
    // 获取callback 参数信息
    JSVM\_Status ret = OH\_JSVM\_GetCbInfo(env, info, &argc, &argv\[0\], &thisArg, &data);
    if (ret != JSVM\_OK) {
        const JSVM\_ExtendedErrorInfo \*info;
        OH\_JSVM\_GetLastErrorInfo(env, &info);
        OH\_LOG\_ERROR(LOG\_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d message = %{public}s",
                     \_\_FILE\_\_, \_\_LINE\_\_, ret, info != nullptr ? info->errorMessage : "");
        return nullptr;
    }
    const int maxMessageLength = 256;
    char message\[256\];
    OH\_JSVM\_GetValueStringLatin1(env, argv\[0\], message, maxMessageLength, nullptr);
    if (data == nullptr) {
        OH\_LOG\_ERROR(LOG\_APP, "jsvm: %{public}s; callback data null", message);
    } else {
        OH\_LOG\_INFO(LOG\_APP, "jsvm: %{public}s; %{public}s", message, (char \*)data);
    }
    return nullptr;
}

static int32\_t TEST\_FUNC()
{
    JSVM\_InitOptions initOptions{};
    JSVM\_VM vm;
    JSVM\_Env env = nullptr;
    JSVM\_VMScope vmScope;
    JSVM\_EnvScope envScope;
    JSVM\_HandleScope handleScope;
    JSVM\_Value result;
    static bool isVMInit = false;
    if (!isVMInit) {
        isVMInit = true;
        // 单个进程只需初始化一次
        OH\_JSVM\_Init(&initOptions);
    }
    CHECK\_RET(OH\_JSVM\_CreateVM(nullptr, &vm));
    CHECK\_RET(OH\_JSVM\_OpenVMScope(vm, &vmScope));
    CHECK\_RET(OH\_JSVM\_CreateEnv(vm, 0, nullptr, &env));
    CHECK\_RET(OH\_JSVM\_OpenEnvScope(env, &envScope));
    CHECK\_RET(OH\_JSVM\_OpenHandleScope(env, &handleScope));

    // 创建并检查函数
    char hello\[\] = "Hello World!";
    JSVM\_CallbackStruct cb = {NativeCreateFunctionTest, (void \*)hello};
    JSVM\_Value func;
    CHECK\_RET(OH\_JSVM\_CreateFunction(env, "", JSVM\_AUTO\_LENGTH, &cb, &func));
    bool isFunction = false;
    CHECK\_RET(OH\_JSVM\_IsFunction(env, func, &isFunction));
    CHECK(isFunction);

    // 将函数设置到全局对象中
    JSVM\_Value global;
    CHECK\_RET(OH\_JSVM\_GetGlobal(env, &global));
    JSVM\_Value key;
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, "NativeFunc", JSVM\_AUTO\_LENGTH, &key));
    CHECK\_RET(OH\_JSVM\_SetProperty(env, global, key, func));

    // 通过call 接口调用函数
    JSVM\_Value argv\[1\] = {nullptr};
    OH\_JSVM\_CreateStringUtf8(env, "jsvm api call function", JSVM\_AUTO\_LENGTH, &argv\[0\]);
    CHECK\_RET(OH\_JSVM\_CallFunction(env, global, func, 1, argv, &result));

    // 通过script调用函数
    JSVM\_Script script;
    JSVM\_Value jsSrc;
    const char \*srcCallNative = R"JS(NativeFunc('js source call function');)JS";
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, srcCallNative, JSVM\_AUTO\_LENGTH, &jsSrc));
    CHECK\_RET(OH\_JSVM\_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));

    CHECK\_RET(OH\_JSVM\_CloseHandleScope(env, handleScope));
    CHECK\_RET(OH\_JSVM\_CloseEnvScope(env, envScope));
    CHECK\_RET(OH\_JSVM\_DestroyEnv(env));
    CHECK\_RET(OH\_JSVM\_CloseVMScope(vm, vmScope));
    CHECK\_RET(OH\_JSVM\_DestroyVM(vm));
    return 0;
}

预期输出结果：

jsvm: jsvm api call function; Hello World!
jsvm: js source call function; Hello World!