HarmonyOS 鸿蒙Next NDK接口jsvm是否可以在同一个应用中启动多个?

发布于 1周前 作者 caililin 来自 鸿蒙OS

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

2 回复

没有限制 可以在同一个应用中启动多个。

使用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;
    }
<span class="hljs-keyword">if</span> (g_envMap.<span class="hljs-title function_">count</span>(envId) == <span class="hljs-number">0</span> || g_envMap[envId] == nullptr) {
    <span class="hljs-title function_">OH_LOG_ERROR</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"EvalUateJS env is null"</span>);
    <span class="hljs-keyword">return</span> nullptr;
}
<span class="hljs-attr">std</span>::string dataStr = <span class="hljs-title function_">napiValueToString</span>(env, args[<span class="hljs-number">1</span>]);
napi_value res = nullptr;
<span class="hljs-attr">std</span>::lock_guard&lt;<span class="hljs-attr">std</span>::mutex&gt; <span class="hljs-title function_">lock_guard</span>(mutexLock);
{
    <span class="hljs-comment">// open handle scope</span>
    JSVM_HandleScope handlescope;
    <span class="hljs-title function_">OH_JSVM_OpenHandleScope</span>(*g_envMap[envId], &amp;handlescope);
    <span class="hljs-comment">// compile js script</span>
    JSVM_Value sourcecodevalue;
    <span class="hljs-title function_">OH_JSVM_CreateStringUtf8</span>(*g_envMap[envId], dataStr.<span class="hljs-title function_">c_str</span>(), dataStr.<span class="hljs-title function_">size</span>(), &amp;sourcecodevalue);
    JSVM_Script script;
    <span class="hljs-title function_">OH_JSVM_CompileScript</span>(*g_envMap[envId], sourcecodevalue, nullptr, <span class="hljs-number">0</span>, <span class="hljs-literal">true</span>, nullptr, &amp;script);
    <span class="hljs-comment">// run js script</span>
    JSVM_Value result;
    <span class="hljs-title function_">OH_JSVM_RunScript</span>(*g_envMap[envId], script, &amp;result);
    JSVM_ValueType type;
    <span class="hljs-title function_">OH_JSVM_Typeof</span>(*g_envMap[envId], result, &amp;type);
    <span class="hljs-title function_">OH_LOG_INFO</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"JSVM API TEST type: %{public}d"</span>, type);
    <span class="hljs-comment">// Execute tasks in the current env event queue</span>
    <span class="hljs-keyword">while</span> (!g_taskQueueMap[envId].<span class="hljs-title function_">empty</span>()) {
        auto task = g_taskQueueMap[envId].<span class="hljs-title function_">front</span>();
        g_taskQueueMap[envId].<span class="hljs-title function_">pop_front</span>();
        task-&gt;<span class="hljs-title class_">Run</span>();
        <span class="hljs-keyword">delete</span> task;
    }

    <span class="hljs-keyword">if</span> (type == <span class="hljs-variable constant_">JSVM_STRING</span>) {
        <span class="hljs-attr">std</span>::string stdResult = <span class="hljs-title function_">fromOHStringValue</span>(*g_envMap[envId], result);
        <span class="hljs-title function_">napi_create_string_utf8</span>(env, stdResult.<span class="hljs-title function_">c_str</span>(), stdResult.<span class="hljs-title function_">length</span>(), &amp;res);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-variable constant_">JSVM_BOOLEAN</span>) {
        bool ret = <span class="hljs-literal">false</span>;
        <span class="hljs-attr">std</span>::string stdResult;
        <span class="hljs-title function_">OH_JSVM_GetValueBool</span>(*g_envMap[envId], result, &amp;ret);
        ret ? stdResult = <span class="hljs-string">"true"</span> : stdResult = <span class="hljs-string">"false"</span>;
        <span class="hljs-title function_">napi_create_string_utf8</span>(env, stdResult.<span class="hljs-title function_">c_str</span>(), stdResult.<span class="hljs-title function_">length</span>(), &amp;res);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-variable constant_">JSVM_NUMBER</span>) {
        int32_t num;
        <span class="hljs-title function_">OH_JSVM_GetValueInt32</span>(*g_envMap[envId], result, &amp;num);
        <span class="hljs-attr">std</span>::string stdResult = <span class="hljs-attr">std</span>::<span class="hljs-title function_">to_string</span>(num);
        <span class="hljs-title function_">napi_create_string_utf8</span>(env, stdResult.<span class="hljs-title function_">c_str</span>(), stdResult.<span class="hljs-title function_">length</span>(), &amp;res);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-variable constant_">JSVM_OBJECT</span>) {
        JSVM_Value objResult;
        <span class="hljs-title function_">OH_JSVM_JsonStringify</span>(*g_envMap[envId], result, &amp;objResult);
        <span class="hljs-attr">std</span>::string stdResult = <span class="hljs-title function_">fromOHStringValue</span>(*g_envMap[envId], objResult);
        <span class="hljs-title function_">napi_create_string_utf8</span>(env, stdResult.<span class="hljs-title function_">c_str</span>(), stdResult.<span class="hljs-title function_">length</span>(), &amp;res);
}
    <span class="hljs-title function_">OH_JSVM_CloseHandleScope</span>(*g_envMap[envId], handlescope);
}
<span class="hljs-title function_">OH_LOG_INFO</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"JSVM EvalUateJS END"</span>);
<span class="hljs-keyword">return</span> 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 = <span class="hljs-title function_">napi_get_value_uint32</span>(env1, argv[<span class="hljs-number">0</span>], &amp;coreEnvId);
<span class="hljs-keyword">if</span> (status != napi_ok) {
    <span class="hljs-title function_">OH_LOG_ERROR</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"JSVM CreateJsCore napi_get_value_uint32 faild"</span>);
    <span class="hljs-keyword">return</span> nullptr;
}
<span class="hljs-keyword">if</span> (g_envMap.<span class="hljs-title function_">count</span>(coreEnvId) == <span class="hljs-number">0</span> ) {
    <span class="hljs-title function_">OH_LOG_ERROR</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"JSVM CreateJsCore not has env "</span>);
    <span class="hljs-keyword">return</span> nullptr;
}
<span class="hljs-keyword">if</span> (g_envMap[coreEnvId] != nullptr) {
    <span class="hljs-attr">std</span>::lock_guard&lt;<span class="hljs-attr">std</span>::mutex&gt; <span class="hljs-title function_">lock_guard</span>(envMapLock);
    <span class="hljs-title function_">OH_JSVM_CloseEnvScope</span>(*g_envMap[coreEnvId], g_envScopeMap[coreEnvId]);
    g_envScopeMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    <span class="hljs-title function_">OH_JSVM_DestroyEnv</span>(*g_envMap[coreEnvId]);
    g_envMap[coreEnvId] = nullptr;
    g_envMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    <span class="hljs-title function_">OH_JSVM_CloseVMScope</span>(*g_vmMap[coreEnvId], g_vmScopeMap[coreEnvId]);
    g_vmScopeMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    <span class="hljs-title function_">OH_JSVM_DestroyVM</span>(*g_vmMap[coreEnvId]);
    g_vmMap[coreEnvId] = nullptr;
    g_vmMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    <span class="hljs-keyword">delete</span> [] g_callBackStructMap[coreEnvId];
    g_callBackStructMap[coreEnvId] = nullptr;
    g_callBackStructMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    <span class="hljs-title function_">napi_delete_reference</span>(env1, g_callBackMap[coreEnvId]);
    g_callBackMap.<span class="hljs-title function_">erase</span>(coreEnvId);
    g_taskQueueMap.<span class="hljs-title function_">erase</span>(coreEnvId);
}
<span class="hljs-title function_">OH_LOG_INFO</span>(<span class="hljs-variable constant_">LOG_APP</span>, <span class="hljs-string">"JSVM ReleaseJsCore END"</span>);
<span class="hljs-keyword">return</span> 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) =&gt; { assertEqual(result, 0); onJSResultCallback(result, "abc", "v"); }); a; };;

        <span class="hljs-keyword">let</span> sourcecodestr1 = <span class="hljs-string">`{
      let a = "second hello";
      consoleinfo(a);
      let b = add(99, 1);
      assertEqual(100, b);"
      "assertEqual(add(99, 1), 100);
      createPromise().then((result) =&gt; {
      assertEqual(result, 1);
      consoleinfo(onJSResultCallback(result, '999','666'));});"
      "a
      };`</span>;

        <span class="hljs-comment">// 创建首个运行环境,并绑定TS回调</span>
        <span class="hljs-keyword">const</span> coreId = testNapi.<span class="hljs-title function_">createJsCore</span>(<span class="hljs-title class_">MyCallback</span>);
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"TEST coreId: "</span> + coreId);
        <span class="hljs-comment">// 在首个运行环境中执行JS代码</span>
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"TEST evalUateJS :   "</span> + testNapi.evalUateJS(coreId, sourceCodeStr));

        <span class="hljs-comment">//创建第二个运行环境,并绑定TS回调</span>
        <span class="hljs-keyword">const</span> coreId1 = testNapi.<span class="hljs-title function_">createJsCore</span>(<span class="hljs-title class_">MyCallback2</span>);
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"TEST coreId: "</span> + coreId1);
        <span class="hljs-comment">// 在第二个运行环境中执行JS代码</span>
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"TEST evalUateJS :   "</span> + testNapi.evalUateJS(coreId1, sourcecodestr1));

        <span class="hljs-comment">// 释放首个运行环境</span>
        testNapi.<span class="hljs-title function_">releaseJsCore</span>(coreId);
        <span class="hljs-comment">// 释放第二个运行环境</span>
        testNapi.<span class="hljs-title function_">releaseJsCore</span>(coreId1);
        hilog.<span class="hljs-title function_">info</span>(<span class="hljs-number">0x0000</span>, <span class="hljs-string">'testTag'</span>, <span class="hljs-string">'Test NAPI end'</span>);
      })
  }
  .<span class="hljs-title function_">width</span>(<span class="hljs-string">'100%'</span>)
}
.<span class="hljs-title function_">height</span>(<span class="hljs-string">'100%'</span>)

} }

总的来说,就是通过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

回到顶部