harmony 鸿蒙使用JSVM-API实现JS与C/C++语言交互开发流程
使用JSVM-API实现JS与C/C++语言交互开发流程
使用JSVM-API实现跨语言交互,首先需要按照JSVM-API的机制实现模块的注册和加载等相关动作。
ArkTS/JS侧:实现C++方法的调用。代码比较简单,import一个对应的so库后,即可调用C++方法。
Native侧:.cpp文件,实现模块的注册。需要提供注册lib库的名称,并在注册回调方法中定义接口的映射关系,即Native方法及对应的JS/ArkTS接口名称等。
此处以在ArkTS/JS侧实现RunJsVm()接口、在Native侧实现RunJsVm()接口,从而实现跨语言交互为例,呈现使用JSVM-API进行跨语言交互的流程。
创建Native C++工程
具体见创建NDK工程
Native侧方法的实现
参考使用Node-API实现跨语言交互开发流程,以下代码提供了“使用JSVM-API实现JS与C/C++语言交互开发流程”Native侧方法实现的一个demo。
- 在index.d.ts文件中,提供JS侧的接口方法。
// entry/src/main/cpp/types/libentry/index.d.ts
export const runTest: () => void;
- 在oh-package.json5文件中将index.d.ts与cpp文件关联起来。
{
"name": "libentry.so",
"types": "./index.d.ts",
"version": "",
"description": "Please describe the basic information."
}
- 在CMakeLists.txt文件中配置CMake打包参数。
# entry/src/main/cpp/CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
project(JSVMDemo)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# 日志打印配置
add_definitions( "-DLOG_DOMAIN=0xd0d0" )
add_definitions( "-DLOG_TAG=\"testTag\"" )
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
# 添加名为entry的库
add_library(entry SHARED hello.cpp)
# 构建此可执行文件需要链接的库
target_link_libraries(entry PUBLIC libace_napi.z.so libjsvm.so libhilog_ndk.z.so)
- 实现Native侧的runTest接口。具体代码如下:
// entry/src/main/cpp/hello.cpp
#include "napi/native_api.h"
#include "hilog/log.h"
#include "ark_runtime/jsvm.h"
#define LOG_DOMAIN 0x3200
#define LOG_TAG "APP"
static int g_aa = 0;
#define CHECK_RET(theCall) \
do { \
JSVM_Status cond = theCall; \
if ((cond) != 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__, cond, info != nullptr ? info->errorMessage : ""); \
return -1; \
} \
} while (0)
#define CHECK(theCall) \
do { \
JSVM_Status cond = theCall; \
if ((cond) != JSVM_OK) { \
OH_LOG_ERROR(LOG_APP, "jsvm fail file: %{public}s line: %{public}d ret = %{public}d", __FILE__, __LINE__, \
cond); \
return -1; \
} \
} while (0)
// 用于调用theCall并检查其返回值是否为JSVM_OK。
// 如果不是,则调用OH_JSVM_GetLastErrorInfo处理错误并返回retVal。
#define JSVM_CALL_BASE(env, theCall, retVal) \
do { \
JSVM_Status cond = theCall; \
if (cond != 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__, cond, info != nullptr ? info->errorMessage : ""); \
return retVal; \
} \
} while (0)
// JSVM_CALL_BASE的简化版本,返回nullptr
#define JSVM_CALL(theCall) JSVM_CALL_BASE(env, theCall, nullptr)
// OH_JSVM_StrictEquals的样例方法
static JSVM_Value IsStrictEquals(JSVM_Env env, JSVM_CallbackInfo info) {
// 接受两个入参
size_t argc = 2;
JSVM_Value args[2] = {nullptr};
JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, nullptr, nullptr));
// 调用OH_JSVM_StrictEquals接口判断给定的两个JavaScript value是否严格相等
bool result = false;
JSVM_Status status = OH_JSVM_StrictEquals(env, args[0], args[1], &result);
if (status != JSVM_OK) {
OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_StrictEquals: failed");
} else {
OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_StrictEquals: success: %{public}d", result);
}
JSVM_Value isStrictEqual;
JSVM_CALL(OH_JSVM_GetBoolean(env, result, &isStrictEqual));
return isStrictEqual;
}
// IsStrictEquals注册回调
static JSVM_CallbackStruct param[] = {
{.data = nullptr, .callback = IsStrictEquals},
};
static JSVM_CallbackStruct *method = param;
// IsStrictEquals方法别名,供JS调用
static JSVM_PropertyDescriptor descriptor[] = {
{"isStrictEquals", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
// 样例测试js
const char *srcCallNative = R"JS( let data = '123';
let value = 123;
isStrictEquals(data,value);)JS";
static int32_t TestJSVM() {
JSVM_InitOptions initOptions = {0};
JSVM_VM vm;
JSVM_Env env = nullptr;
JSVM_VMScope vmScope;
JSVM_EnvScope envScope;
JSVM_HandleScope handleScope;
JSVM_Value result;
// 初始化JavaScript引擎实例
if (g_aa == 0) {
g_aa++;
CHECK(OH_JSVM_Init(&initOptions));
}
// 创建JSVM环境
CHECK(OH_JSVM_CreateVM(nullptr, &vm));
CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env));
CHECK(OH_JSVM_OpenVMScope(vm, &vmScope));
CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope));
CHECK_RET(OH_JSVM_OpenHandleScope(env, &handleScope));
// 通过script调用测试函数
JSVM_Script script;
JSVM_Value jsSrc;
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));
// 销毁JSVM环境
CHECK_RET(OH_JSVM_CloseHandleScope(env, handleScope));
CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope));
CHECK(OH_JSVM_CloseVMScope(vm, vmScope));
CHECK(OH_JSVM_DestroyEnv(env));
CHECK(OH_JSVM_DestroyVM(vm));
return 0;
}
static napi_value RunTest(napi_env env, napi_callback_info info)
{
TestJSVM();
return nullptr;
}
// 模块初始化
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
// 实现ArkTS接口与C++接口的绑定和映射
napi_property_descriptor desc[] = {
{"runTest", nullptr, RunTest, nullptr, nullptr, nullptr, napi_default, nullptr}
};
// 在exports对象上挂载RunJsVm的Native方法
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
ArkTS侧调用C/C++方法实现
import hilog from '@ohos.hilog';
// 通过import的方式,引入Native能力。
import napitest from 'libentry.so';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
// runtest
napitest.runTest();
})
}
.width('100%')
}
.height('100%')
}
}
预期输出结果
JSVM OH_JSVM_StrictEquals: success: 0
你可能感兴趣的鸿蒙文章
0
赞
- 所属分类: 后端技术
- 本文标签:
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦