openharmony 鸿蒙 use-napi-about-context

2026-08-25 浏览 (1)

Creating, Switching, and Destroying a Context in a Thread Using Node-API Extension APIs

When an application is started, the main thread of the application is an ArkTS thread, which has a context managed by the system. When ArkTS interacts with C/C++, napi_env represents the context on the C/C++ side. Every context has an independent globalThis object.

You can use the extension APIs napi_create_ark_context and napi_destroy_ark_context in Node-API to create and destroy a new context in the current thread. The new context and the original context in the thread share the same runtime virtual machine.

Note that napi_create_ark_context creates a new context but not a new runtime. The context created by this API must be destroyed by napi_destroy_ark_context. Otherwise, memory leaks may occur.

The original context of the ArkTS thread cannot be destroyed using the napi_destroy_ark_context API.

To switch to a specified context, you can call the extension API napi_switch_ark_context in the Node-API.

You can access some properties and methods on globalThis in a new context, and then switch back to the original context to ensure context isolation.

Scenario

You can use the napi_create_ark_context API to create a context environment in the current thread, which has an independent globalThis object.

This indicates that the original context on the current thread is isolated from the newly created context , that is, the globalThis objects in the contexts are different.

You can use the newly created context to load modular objects, which are mounted to the globalThis object in the current context. Different modules are loaded to different contexts. This prevents one module's changes to globalThis from affecting another module's access to globalThis.

Some standard and extension APIs of the Node-API are context-adaptive. When these APIs are called, the context is automatically switched based on the input parameter napi_env. You do not need to call napi_switch_ark_context to switch the context.

Note that when returning from the C++/C side to the ArkTS side, you need to call napi_switch_ark_context to switch the context back to the corresponding context. Otherwise, the ArkTS code will be executed in another context, causing unpredictable stability issues.

Node-APIs That Support Multi-Runtime Context

The following table lists the Node-APIs that can be executed in a multi-context environment. Some of these Node-APIs can automatically switch the context.

Even if napi_switch_ark_context is not actively called to switch the runtime context, these APIs can still determine whether to switch the context by comparing whether the runtime context is the same as the runtime environment specified by the API.

If the contexts are inconsistent, these Node-APIs switch the current runtime environment to the context specified by the API parameters.

If an API does not involve context switching, it is irrelevant to the runtime context and can be executed in any valid context.

APIWhether to Proactively Switch the Context
napi_module_registerNo
napi_fatal_errorNo
napi_async_initYes
napi_async_destroyNo
napi_make_callbackYes
napi_create_bufferYes
napi_create_external_bufferYes
napi_create_buffer_copyYes
napi_is_bufferNo
napi_get_buffer_infoNo
napi_create_async_workYes
napi_delete_async_workNo
napi_queue_async_workNo
napi_cancel_async_workNo
napi_get_node_versionNo
napi_fatal_exceptionNo
napi_add_env_cleanup_hookNo
napi_remove_env_cleanup_hookNo
napi_open_callback_scopeNo
napi_close_callback_scopeNo
napi_create_threadsafe_functionYes
napi_get_threadsafe_function_contextNo
napi_call_threadsafe_functionNo
napi_acquire_threadsafe_functionNo
napi_release_threadsafe_functionNo
napi_unref_threadsafe_functionNo
napi_ref_threadsafe_functionNo
napi_add_async_cleanup_hookNo
napi_remove_async_cleanup_hookNo
node_api_get_module_file_nameNo
napi_get_last_error_infoNo
napi_get_undefinedNo
napi_get_nullNo
napi_get_globalNo
napi_get_booleanNo
napi_create_objectNo
napi_create_arrayNo
napi_create_array_with_lengthNo
napi_create_doubleNo
napi_create_int32No
napi_create_uint32No
napi_create_int64No
napi_create_string_latin1No
napi_create_string_utf8No
napi_create_string_utf16No
napi_create_external_string_asciiNo
napi_create_external_string_utf16No
napi_create_symbolNo
napi_create_functionYes
napi_create_errorYes
napi_create_type_errorYes
napi_create_range_errorYes
napi_typeofNo
napi_get_value_doubleNo
napi_get_value_int32No
napi_get_value_uint32No
napi_get_value_int64No
napi_get_value_boolNo
napi_get_value_string_latin1No
napi_get_value_string_utf8No
napi_get_value_string_utf16No
napi_coerce_to_boolNo
napi_coerce_to_numberYes
napi_coerce_to_objectYes
napi_coerce_to_stringYes
napi_get_prototypeYes
napi_get_property_namesYes
napi_set_propertyYes
napi_has_propertyYes
napi_get_propertyYes
napi_delete_propertyYes
napi_has_own_propertyYes
napi_set_named_propertyYes
napi_has_named_propertyYes
napi_get_named_propertyYes
napi_set_elementYes
napi_has_elementYes
napi_get_elementYes
napi_delete_elementYes
napi_define_propertiesYes
napi_is_arrayNo
napi_get_array_lengthNo
napi_strict_equalsNo
napi_call_functionNo
napi_new_instanceYes
napi_instanceofYes
napi_get_cb_infoNo
napi_get_new_targetNo
napi_define_classYes
napi_wrapYes
napi_unwrapYes
napi_remove_wrapYes
napi_create_externalNo
napi_get_value_externalNo
napi_create_referenceNo
napi_delete_referenceNo
napi_reference_refNo
napi_reference_unrefNo
napi_get_reference_valueNo
napi_open_handle_scopeNo
napi_close_handle_scopeNo
napi_open_escapable_handle_scopeNo
napi_close_escapable_handle_scopeNo
napi_escape_handleNo
napi_throwNo
napi_throw_errorYes
napi_throw_type_errorYes
napi_throw_range_errorYes
napi_is_errorNo
napi_is_exception_pendingNo
napi_get_and_clear_last_exceptionNo
napi_is_arraybufferNo
napi_create_arraybufferNo
napi_create_external_arraybufferNo
napi_get_arraybuffer_infoNo
napi_is_typedarrayNo
napi_create_typedarrayNo
napi_get_typedarray_infoNo
napi_create_dataviewYes
napi_is_dataviewNo
napi_get_dataview_infoNo
napi_get_versionNo
napi_create_promiseYes
napi_resolve_deferredNo
napi_reject_deferredNo
napi_is_promiseNo
napi_run_scriptNo
napi_create_dateYes
napi_is_dateNo
napi_get_date_valueNo
napi_add_finalizerNo
napi_create_bigint_int64No
napi_create_bigint_uint64No
napi_create_bigint_wordsYes
napi_get_value_bigint_int64No
napi_get_value_bigint_uint64No
napi_get_value_bigint_wordsNo
napi_get_all_property_namesNo
napi_set_instance_dataNo
napi_get_instance_dataNo
napi_detach_arraybufferNo
napi_is_detached_arraybufferNo
napi_type_tag_objectNo
napi_check_object_type_tagYes
napi_object_freezeYes
napi_object_sealYes
napi_run_script_pathYes
napi_queue_async_work_with_qosNo
napi_load_moduleYes
napi_create_object_with_propertiesYes
napi_create_object_with_named_propertiesYes
napi_coerce_to_native_binding_objectYes
napi_load_module_with_infoYes
napi_create_ark_runtimeNo
napi_destroy_ark_runtimeNo
napi_serializeYes
napi_deserializeYes
napi_delete_serialization_dataNo
napi_call_threadsafe_function_with_priorityNo
napi_wrap_enhanceYes
napi_open_critical_scopeNo
napi_close_critical_scopeNo
napi_get_buffer_string_utf16_in_critical_scopeNo
napi_create_strong_referenceNo
napi_delete_strong_referenceNo
napi_get_strong_reference_valueNo
napi_throw_business_errorYes

Node-APIs That Do Not Support Multi-Runtime Context

APIReturn Value of Multi-Runtime Context Call
napi_define_sendable_classnapi_invalid_arg
napi_is_sendablenapi_invalid_arg
napi_create_sendable_object_with_propertiesnapi_invalid_arg
napi_wrap_sendablenapi_invalid_arg
napi_wrap_sendable_with_sizenapi_invalid_arg
napi_unwrap_sendablenapi_invalid_arg
napi_remove_wrap_sendablenapi_invalid_arg
napi_create_sendable_arraynapi_invalid_arg
napi_create_sendable_array_with_lengthnapi_invalid_arg
napi_create_sendable_arraybuffernapi_invalid_arg
napi_create_sendable_typedarraynapi_invalid_arg
napi_run_event_loopnapi_invalid_arg
napi_stop_event_loopnapi_invalid_arg
napi_get_uv_event_loopnapi_invalid_arg
napi_create_strong_sendable_referencenapi_invalid_arg
napi_delete_strong_sendable_referencenapi_invalid_arg
napi_get_strong_sendable_reference_valuenapi_invalid_arg

Sample Code

  • Module registration

    // napi_init.cpp
    #include "napi/native_api.h"
    #include "hilog/log.h"
    
    static napi_value NAPI_Global_callFunctionInContext(napi_env env, napi_callback_info info)
    {
        napi_status status = napi_ok;
        size_t argc = 1;
        napi_value args[1] = {nullptr};
        if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) {
            return nullptr;
        }
        // Load the plugin1.ets module in the original context.
        napi_value plugin1 = nullptr;
        status = napi_load_module_with_info(env, "entry/src/main/ets/pages/plugin1", "com.example.myapplication/entry", &plugin1);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "load plugin1 failed");
        }
        // Obtain the GetLocation method in the plugin1 module.
        napi_value getLocation1 = nullptr;
        status = napi_get_named_property(env, plugin1, "GetLocation", &getLocation1);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "obtain GetLocation from plugin1 failed");
        }
        // Create a new context newEnv2.
        napi_env newEnv2 = nullptr;
        status = napi_create_ark_context(env, &newEnv2);
        if (status != napi_ok) {
            return nullptr;
        }
        // Proactively switch to the new context newEnv2.
        status = napi_switch_ark_context(newEnv2);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "switch to newEnv2 failed");
        }
        napi_value plugin2 = nullptr;
        // Load the plugin2.ets module in the new context.
        status = napi_load_module_with_info(newEnv2, "entry/src/main/ets/pages/plugin2", "com.example.myapplication/entry",
                                            &plugin2);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "load plugin2 failed");
        }
    
        napi_value getLocation2 = nullptr;
        status = napi_get_named_property(newEnv2, plugin2, "GetLocation", &getLocation2);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "obtain GetLocation from plugin2 failed");
        }
    
        // Execute the getLocation method on the ArkTS side in the new context. The input parameter is the GetLocation method in the plugin2 module.
        napi_value result = nullptr;
        napi_value args2[1] = {};
        args2[0] = getLocation2;
    
        status = napi_call_function(newEnv2, nullptr, args[0], 1, args2, &result);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "call function of env failed");
        }
        int32_t ret = 0;
        status = napi_get_value_int32(newEnv2, result, &ret);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "napi_get_value_int32 of env failed");
        } else {
            // The value of globalThis.a in the context of plugin2 is 3000.
            OH_LOG_INFO(LOG_APP, "ret is %{public}d", ret); // 3000
        }
        // Proactively switch back to the original context env.
        status = napi_switch_ark_context(env);
        if (status != napi_ok) {
            OH_LOG_INFO(LOG_APP, "switch to env failed");
        }
        args2[0] = getLocation1;
        status = napi_call_function(env, nullptr, args[0], 1, args2, &result);
        if (status != napi_ok) {
            return nullptr;
        }
        // Obtain the value returned after the GetLocation API is called.
        ret = 0;
        status = napi_get_value_int32(env, result, &ret);
        if (status != napi_ok) {
            return nullptr;
        } else {
            // The value of globalThis.a in the context of plugin1 is 2000.
            OH_LOG_INFO(LOG_APP, "ret is %{public}d", ret); // 2000
        }
        // Destroy the created context.
        status = napi_destroy_ark_context(newEnv2);
        if (status != napi_ok) {
            return nullptr;
        }
        return result;
    }
    
    // Register the module.
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
            {"callFunctionInContext", nullptr, NAPI_Global_callFunctionInContext,
                nullptr, nullptr, nullptr, napi_default, nullptr}
        };
        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);
    }
    
  • API declaration

    // index.d.ts
    export const callFunctionInContext: (func: (func:()=>number)=>{}) => number;
    
  • Compilation configuration

  1. Configure the CMakeLists.txt file as follows:

    // CMakeLists.txt
    # the minimum version of CMake.
    cmake_minimum_required(VERSION 3.5.0)
    project(MyApplication8)
    
    set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
    
    if(DEFINED PACKAGE_FIND_FILE)
        include(${PACKAGE_FIND_FILE})
    endif()
    
    add_definitions( "-DLOG_DOMAIN=0xd0d0" )
    add_definitions( "-DLOG_TAG=\"testTag\"")
    
    include_directories(${NATIVERENDER_ROOT_PATH}
                        ${NATIVERENDER_ROOT_PATH}/include)
    
    add_library(entry SHARED napi_init.cpp)
    target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
    
  2. Add the following to the build-profile.json5 file of the project.

    {
        "buildOption" : {
            "arkOptions" : {
                "runtimeOnly" : {
                    "sources": [
                        "./src/main/ets/pages/plugin1.ets",
                        "./src/main/ets/pages/plugin2.ets"
                    ]
                }
            }
        }
    }
    
  • ArkTS sample code
    // index.ets
    import testNapi from "libentry.so"
    // Execute the GetLocation method in the plugin1 or plugin2 module.
    function getLocation(func: () => number) {
        return func();
    }
    testNapi.callFunctionInContext(getLocation)
    
    // ets/pages/plugin1.ets
    globalThis.a = 2000;
    
    export function GetLocation() : number {
        return globalThis.a;
    }
    
    // ets/pages/plugin2.ets
    globalThis.a = 3000;
    
    export function GetLocation() : number {
    return globalThis.a;
    }
    

你可能感兴趣的鸿蒙文章

openharmony 鸿蒙 use-napi-ark-runtime

openharmony 鸿蒙 use-napi-about-arraybuffer

openharmony 鸿蒙 use-jsvm-about-array

openharmony 鸿蒙 use-napi-load-module

openharmony 鸿蒙 jsvm-data-types-interfaces

openharmony 鸿蒙 ohos-abi

openharmony 鸿蒙 jsvm-guidelines

openharmony 鸿蒙 use-jsvm-trigger-gc

openharmony 鸿蒙 use-sendable-napi

openharmony 鸿蒙 use-napi-object-wrap

  • 所属分类: 后端技术
  • 本文标签: 软件 鸿蒙
  • 版权声明: 本文链接 https://seaxiang.com/blog/CCoMMqoz