HarmonyOS 鸿蒙Next NDK接口jsvm是否可以在同一个应用中启动多个?
你好,请问ndk接口jsvm库可以初始化多个吗? 这是我的初始化代码,发现这样初始化jsvm后,全局只能初始化一遍,去掉去重的代码就是VM_INIT判断后,运行,当我尝试多次初始化,进程似乎会陷入无限循环中,直接卡死。
if (!VM_INIT) {
// JSVM only need init once
JSVM_InitOptions initOptions;
memset(&initOptions, 0, sizeof(initOptions));
//initOptions.externalReferences = externals;
OH_JSVM_Init(&initOptions);
PrintVmInfo();
VM_INIT = true;
}
// 创建虚拟机实例
OH_JSVM_CreateVM(nullptr, &vm);
OH_JSVM_OpenVMScope(vm, &vmScope);
//创建js运行环境上下文
JSVM_PropertyDescriptor descriptor[] = {
{"setTimeout", NULL, &set_timeout_cb, NULL, NULL, NULL, JSVM_DEFAULT},
{"clearTimeout", NULL, &clear_timeout_cb, NULL, NULL, NULL, JSVM_DEFAULT},
{"setInterval", NULL, &set_interval_cb, NULL, NULL, NULL, JSVM_DEFAULT},
{"clearInterval", NULL, &clear_interval_cb, NULL, NULL, NULL, JSVM_DEFAULT},
};
OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &jsvm_env);
return jsvm_env;
请问是否jsvm在设计上,一个应用只能启动一个jscore环境?如果想要能同时存在多个,该如何做?
更多关于HarmonyOS 鸿蒙Next NDK接口jsvm是否可以在同一个应用中启动多个?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
没有限制 可以在同一个应用中启动多个。
使用JSVM-API接口创建多个引擎执行JS代码并销毁,可以参考下:
1、提供创建JSVM运行环境的对外接口并返回对应唯一ID:
static napi_value CreateJsCore(napi_env env1, napi_callback_info info) {
OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore START");
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr);
if (argc < 1) {
OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore the number of params must be one");
return nullptr;
}
g_napiEnvMap[ENVTAG_NUMBER] = env1;
g_taskQueueMap[ENVTAG_NUMBER] = deque<Task *>{};
// 将TS侧传入的回调函数与env对应存储方便后续调用
napi_ref callFun;
napi_create_reference(env1, argv[0], 1, &callFun);
g_callBackMap[ENVTAG_NUMBER] = callFun;
napi_value coreID = 0;
{
std::lock_guard<std::mutex> lock_guard(envMapLock);
CreateArkJSContext();
napi_create_uint32(env1, ENVTAG_NUMBER, &coreID);
ENVTAG_NUMBER++;
}
OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore END");
return coreID;
}
2、对外提供执行JS代码接口,通过coreID在对应的JSVN环境中执行JS代码
static napi_value EvalUateJS(napi_env env, napi_callback_info info) {
OH_LOG_INFO(LOG_APP, "JSVM EvalUateJS START");
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
uint32_t envId;
napi_status status = napi_get_value_uint32(env, args[0], &envId);
if (status != napi_ok) {
OH_LOG_ERROR(LOG_APP, "EvalUateJS first param should be number");
return nullptr;
}
if (g_envMap.count(envId) == 0 || g_envMap[envId] == nullptr) {
OH_LOG_ERROR(LOG_APP, "EvalUateJS env is null");
return nullptr;
}
std::string dataStr = napiValueToString(env, args[1]);
napi_value res = nullptr;
std::lock_guard<std::mutex> lock_guard(mutexLock);
{
// open handle scope
JSVM_HandleScope handlescope;
OH_JSVM_OpenHandleScope(*g_envMap[envId], &handlescope);
// compile js script
JSVM_Value sourcecodevalue;
OH_JSVM_CreateStringUtf8(*g_envMap[envId], dataStr.c_str(), dataStr.size(), &sourcecodevalue);
JSVM_Script script;
OH_JSVM_CompileScript(*g_envMap[envId], sourcecodevalue, nullptr, 0, true, nullptr, &script);
// run js script
JSVM_Value result;
OH_JSVM_RunScript(*g_envMap[envId], script, &result);
JSVM_ValueType type;
OH_JSVM_Typeof(*g_envMap[envId], result, &type);
OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type);
// Execute tasks in the current env event queue
while (!g_taskQueueMap[envId].empty()) {
auto task = g_taskQueueMap[envId].front();
g_taskQueueMap[envId].pop_front();
task->Run();
delete task;
}
if (type == JSVM_STRING) {
std::string stdResult = fromOHStringValue(*g_envMap[envId], result);
napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
} else if (type == JSVM_BOOLEAN) {
bool ret = false;
std::string stdResult;
OH_JSVM_GetValueBool(*g_envMap[envId], result, &ret);
ret ? stdResult = "true" : stdResult = "false";
napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
} else if (type == JSVM_NUMBER) {
int32_t num;
OH_JSVM_GetValueInt32(*g_envMap[envId], result, &num);
std::string stdResult = std::to_string(num);
napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
} else if (type == JSVM_OBJECT) {
JSVM_Value objResult;
OH_JSVM_JsonStringify(*g_envMap[envId], result, &objResult);
std::string stdResult = fromOHStringValue(*g_envMap[envId], objResult);
napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
}
OH_JSVM_CloseHandleScope(*g_envMap[envId], handlescope);
}
OH_LOG_INFO(LOG_APP, "JSVM EvalUateJS END");
return res;
}
3、对外提供释放JSVM环境接口,通过envId释放对应环境
static napi_value ReleaseJsCore(napi_env env1, napi_callback_info info) {
OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore START");
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr);
if (argc < 1) {
OH_LOG_ERROR(LOG_APP, "JSVM ReleaseJsCore the number of params must be one");
return nullptr;
}
uint32_t coreEnvId;
napi_status status = napi_get_value_uint32(env1, argv[0], &coreEnvId);
if (status != napi_ok) {
OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore napi_get_value_uint32 faild");
return nullptr;
}
if (g_envMap.count(coreEnvId) == 0 ) {
OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore not has env ");
return nullptr;
}
if (g_envMap[coreEnvId] != nullptr) {
std::lock_guard<std::mutex> lock_guard(envMapLock);
OH_JSVM_CloseEnvScope(*g_envMap[coreEnvId], g_envScopeMap[coreEnvId]);
g_envScopeMap.erase(coreEnvId);
OH_JSVM_DestroyEnv(*g_envMap[coreEnvId]);
g_envMap[coreEnvId] = nullptr;
g_envMap.erase(coreEnvId);
OH_JSVM_CloseVMScope(*g_vmMap[coreEnvId], g_vmScopeMap[coreEnvId]);
g_vmScopeMap.erase(coreEnvId);
OH_JSVM_DestroyVM(*g_vmMap[coreEnvId]);
g_vmMap[coreEnvId] = nullptr;
g_vmMap.erase(coreEnvId);
delete [] g_callBackStructMap[coreEnvId];
g_callBackStructMap[coreEnvId] = nullptr;
g_callBackStructMap.erase(coreEnvId);
napi_delete_reference(env1, g_callBackMap[coreEnvId]);
g_callBackMap.erase(coreEnvId);
g_taskQueueMap.erase(coreEnvId);
}
OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore END");
return nullptr;
}
cpp目录下导出接口 Index.d.ts
// index.d.ts
export const createJsCore: (fun: Function) => number;
export const releaseJsCore: (a: number) => void;
export const evalUateJS: (a: number, str: string) => string;
使用接口 pages/Index.ets
import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';
function MyCallback(a: string, b: string): string {
console.log("TEST MyCallback run: " + a);
b = "callback done";
console.log("TEST MyCallback run: " + b);
return "callback pass";
}
function MyCallback2(a: string, b: string): string {
console.log("TEST MyCallback2 start: a = " + a);
console.log("TEST MyCallback2 start: b = " + b);
return "MyCallback2 pass";
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let sourceCodeStr = `{
let a = "hello World";
consoleinfo(a);
const mPromise = createPromise();
mPromise.then((result) => {
assertEqual(result, 0);
onJSResultCallback(result, "abc", "v");
});
a;
};`;
let sourcecodestr1 = `{
let a = "second hello";
consoleinfo(a);
let b = add(99, 1);
assertEqual(100, b);"
"assertEqual(add(99, 1), 100);
createPromise().then((result) => {
assertEqual(result, 1);
consoleinfo(onJSResultCallback(result, '999','666'));});"
"a
};`;
// 创建首个运行环境,并绑定TS回调
const coreId = testNapi.createJsCore(MyCallback);
console.log("TEST coreId: " + coreId);
// 在首个运行环境中执行JS代码
console.log("TEST evalUateJS : " + testNapi.evalUateJS(coreId, sourceCodeStr));
//创建第二个运行环境,并绑定TS回调
const coreId1 = testNapi.createJsCore(MyCallback2);
console.log("TEST coreId: " + coreId1);
// 在第二个运行环境中执行JS代码
console.log("TEST evalUateJS : " + testNapi.evalUateJS(coreId1, sourcecodestr1));
// 释放首个运行环境
testNapi.releaseJsCore(coreId);
// 释放第二个运行环境
testNapi.releaseJsCore(coreId1);
hilog.info(0x0000, 'testTag', 'Test NAPI end');
})
}
.width('100%')
}
.height('100%')
}
}
总的来说,就是通过createJsCore方法来创建一个新的JS基础运行时环境,并通过该方法获得一个CoreID,通过evalUateJS方法使用CoreID对应的运行环境来运行JS代码,在JS代码中创建promise并异步调取TS侧设定的callback函数,最后使用releaseJsCore方法来释放CoreID对应的运行环境。
更多关于HarmonyOS 鸿蒙Next NDK接口jsvm是否可以在同一个应用中启动多个?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS 鸿蒙Next NDK接口中的jsvm
(JavaScript虚拟机)支持在同一个应用中启动多个实例。每个jsvm
实例在运行时是独立的,彼此之间的执行环境和状态不会相互干扰。这意味着开发者可以在单个应用中根据需要创建并管理多个JavaScript虚拟机实例,以实现更复杂的逻辑处理和功能隔离。
例如,如果你的应用需要同时运行多个独立的JavaScript代码块,每个代码块可能需要不同的全局变量、函数定义和执行上下文,那么你可以为每个代码块创建一个独立的jsvm
实例。这样做可以提高应用的模块化和可维护性,同时避免不同代码块之间的潜在冲突。
需要注意的是,启动多个jsvm
实例会占用更多的系统资源,包括内存和处理器时间。因此,在决定使用多个jsvm
实例时,开发者应该权衡资源消耗和性能需求,确保应用的稳定性和用户体验。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。