HarmonyOS鸿蒙Next中调用napi_create_threadsafe_function创建的js callback安全函数,传进CallJs函数的js_cb为0

HarmonyOS鸿蒙Next中调用napi_create_threadsafe_function创建的js callback安全函数,传进CallJs函数的js_cb为0 测试环境是windows的phone模拟器,使用SDK 5.0.3(15)

先使用napi_create_threadsafe_function创建了封装arkts函数的安全函数,得到tsfn。

然后在asyncwork的execute函数中使用tsfn调用napi_call_threadsafe_function,

但传进CallJs函数的js_cb为0x0,怀疑是被GC了。

workaround方法是,在使用napi_get_cb_info得到js的callback函数地址value后封装成napi_ref,再通过context方式送入CallJs函数,再提取ref得到js函数的value。

问题是是如何保证napi_create_threadsafe_function封装的CallJs得到的js_cb value是有效的?

是否将这个类型从value改成ref比较好。


更多关于HarmonyOS鸿蒙Next中调用napi_create_threadsafe_function创建的js callback安全函数,传进CallJs函数的js_cb为0的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

arkts:

testNapi.registerStringCallback((msg: string) => {
  hilog.info(DOMAIN, 'napi string callback get msg %{public}s', msg);
})

native:

void CallJs(napi_env env, napi_value js_cb, void* context, void* data) {
    auto msg = reinterpret_cast<std::string*>(data);
    InitContextData *asyncData = reinterpret_cast<InitContextData*>(context);
    // 此时js_cb传入是0x0
    napi_get_reference_value(env, asyncData->callbackRef, &js_cb);
    // 经过deref后js_cb恢复为真正的js函数地址
    napi_value argv[1];
    napi_create_string_utf8(env, msg->c_str(), NAPI_AUTO_LENGTH, &argv[0]);
    
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    // 不经过上述deref,直接使用传入的js_cb原始值不会成功
    napi_call_function(env, undefined, js_cb, 1, argv, nullptr);
}

static napi_value RegisterStringCallback(napi_env env, napi_callback_info info) {
    InitContextData *asyncData = nullptr;

    napi_value jsCb = nullptr;
    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&asyncData));
    // napi_value转换为napi_ref
    napi_create_reference(env, jsCb, 1, &asyncData->callbackRef);

    // 创建安全函数
    napi_create_threadsafe_function(
        env,
        nullptr,
        jsCb, // 一定被GC掉
        resourceName,
        0,
        1,
        asyncData,
        nullptr,
        asyncData,
        CallJs,
        &asyncData->tsfn
    );
    // 创建async work
    napi_create_async_work(
        env,
        nullptr,
        asyncWorkName,
        [](napi_env env, void* data) {
            InitContextData *asyncData = reinterpret_cast<InitContextData*>(data);
                std::string msg = "Update Success";
                // 调用安全的js函数
                napi_call_threadsafe_function(
                    asyncData->tsfn,
                    new std::string(msg),
                    napi_tsfn_blocking
                );
            }
        },
    );
}

调试结果如下:

经过deref后才拿到正确的callback地址

无标题图片

更多关于HarmonyOS鸿蒙Next中调用napi_create_threadsafe_function创建的js callback安全函数,传进CallJs函数的js_cb为0的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


您好,为了更快速解决您的问题,并且吸引更多用户一同参与您问题的解答与讨论,建议您补全如下信息:

补全复现代码,让参与用户更快速复现您的问题;

更多提问技巧,请参考:【Tips】如何提个好问题

在HarmonyOS鸿蒙Next中,如果napi_create_threadsafe_function创建的JS回调函数在CallJs时传入的js_cb为0,可能是由于JS回调函数被垃圾回收(GC)机制回收。为避免此问题,建议在创建线程安全函数后,使用napi_reference_ref增加对JS回调的引用计数,确保其在调用期间不被GC回收。调用完成后,使用napi_reference_unref减少引用计数,避免内存泄漏。

回到顶部