HarmonyOS鸿蒙Next中如何在Native侧C++子线程直接调用ArkTS接口,不用通过ArkTS侧触发回调
HarmonyOS鸿蒙Next中如何在Native侧C++子线程直接调用ArkTS接口,不用通过ArkTS侧触发回调 如题,举例:
项目中使用了官方的 Native 库:
#include "network/netstack/net_websocket.h"
这是一个WebSocket库,连接websocket后如果触发OnMessage回调,想要将收到的消息发到 ArkTS 侧来显示,反正我想到的最直接的方式是直接调用 ArkTS 中的一个方法回调,但当前的版本并不支持,下面是官方QA的回复:
当前版本仅支持在ArkTS侧触发Native方法后回调ArkTS接口。
我觉得我的这种需求不算罕见吧,竟然不支持。再吐槽一句,官方目前这种调用方式也太鸡肋了,将 ArkTS 的方法传输到 C++ 侧调用… 主动调用 C++方法,再在 C++侧调用传入的 ArkTS方法。我实在想不到使用场景。
我也不等更新了,在线寻求一个能实现上面需求的方法。
更多关于HarmonyOS鸿蒙Next中如何在Native侧C++子线程直接调用ArkTS接口,不用通过ArkTS侧触发回调的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【背景知识】 许多涉及到跟设备交互的应用,都需要使用C++去跟设备交互,然后在C++中去创建子线程去接收设备返回来的信息,需要在C++子线程中调用ArkTS的方法,去把数据传到ArkTS中。
【解决方案】 在C++侧创建ArkTS线程安全函数:
struct CallbackObj {
// arkts方法引用
napi_ref cbObj;
// 线程安全函数
napi_threadsafe_function tsfn;
};
CallbackObj *callBack = new CallbackObj();
static napi_value NAPI_Global_setCallback(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CallbackObj *downLoadCallBack = new CallbackObj();
napi_value workName;
// 指向napi_value js_cb 的 napi_ref cbObj,js_cb为获取到的arkts回调方法
napi_create_reference(env, args[0], 1, &callBack->cbObj);
// 通过UTF8编码的C字符串数据创建work_name
napi_create_string_utf8(env, "DownLoadCallBack Work", NAPI_AUTO_LENGTH, &workName;);
// 创建线程安全函数,存到tsfn中
napi_create_threadsafe_function(env, args[0], NULL, workName, 0, 1, NULL, NULL, NULL, downLoadCallback, &callBack->tsfn);
return nullptr;
}
void downLoadCallback(napi_env env, napi_value js_cb, void *context, void *data) {
int connectState = *(int *)data;
// 获取引用值
OH_LOG_INFO(LOG_APP, "进入connectStateCallback");
// 创建一个ArkTS number作为ArkTS function的入参。
napi_value argv;
napi_create_int32(env, connectState, &argv);
// 调用回调函数
int num;
napi_value result = nullptr;
napi_call_function(env, nullptr, js_cb, 1, &argv, &result);
napi_get_value_int32(env, result, &num);
}
在C++的子线程中调用ArkTS方法:
在子线程中获取线程安全函数并执行:
napi_acquire_threadsafe_function(callBack->tsfn);
napi_call_threadsafe_function(callBack->tsfn, connectState, napi_tsfn_blocking);
在ArkTS中调用函数:
import nativeFun from 'libentry.so';
@Entry
@Component
struct Index {
@State message: string = '';
build() {
Row() {
Column() {
Text(this.message)
.onClick(() => {
nativeFun.nativeCallArkTS((a: number)=> {
a++;
this.message = a.toString()
return a })
})
}
.width('100%')
}
.height('100%')
}
}
更多关于HarmonyOS鸿蒙Next中如何在Native侧C++子线程直接调用ArkTS接口,不用通过ArkTS侧触发回调的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
提供一段代码看看能不能帮助你
ArkTS侧注册回调
import webSocket from '@kit.NetworkKit';
import nativeBridge from 'libnative.so';
class WebSocketHandler {
onMessageReceived = (data: string) => {
console.log('收到消息:', data);
// 更新UI显示逻辑
}
initWebSocket() {
const ws = webSocket.createWebSocket();
nativeBridge.registerMessageCallback(this.onMessageReceived);
ws.connect('ws://example.com');
}
}
Native侧桥接层
// 创建线程安全函数
napi_value RegisterCallback(napi_env env, napi_callback_info info) {
napi_value jsCallback;
napi_get_cb_info(env, info, nullptr, nullptr, &jsCallback, nullptr);
auto ctx = new ThreadContext();
napi_create_threadsafe_function(env, jsCallback,
nullptr, napi_tsfn_create_new,
0, 1, ctx, FinalizeCallback, &ctx->tsfn);
napi_acquire_threadsafe_function(ctx->tsfn);
return nullptr;
}
// WebSocket消息回调
void OnWebSocketMessage(void* data) {
ThreadContext* ctx = static_cast<ThreadContext*>(data);
const char* message = "从Native接收的数据";
napi_call_threadsafe_function(ctx->tsfn, message, napi_tsfn_blocking);
}
WebSocket子线程中禁止直接操作ArkTS对象
通过napi_call_threadsafe_function实现异步队列化调用
二进制数据建议使用ArrayBuffer传输
// 传递二进制数据示例
napi_value buffer;
napi_create_arraybuffer(env, dataSize, &rawData, &buffer);
napi_call_threadsafe_function(ctx->tsfn, buffer, napi_tsfn_blocking);
楼主好,我来啦哈哈,加不加分不重要,主要我喜欢话痨。
Node-API提供的napi_create_threadsafe_function他这个允许在子线程中安全调用ArkTS函数。内部通过任务队列管理调用顺序,可以保证主线程按序执行回调。然后子线程通过napi_call_threadsafe_function投递任务,主线程异步处理。要注意napi_env仅在主线程有效,子线程需通过线程安全函数绕开直接操作napi_value的限制。这样无需ArkTS主动触发Native方法,通过模块初始化时注册回调实现主动调用。
废话不多直接上步骤:
ArkTS侧注册回调函数
// index.ets
import testNapi from 'libentry.so';
@Entry
@Component
struct Index {
@State message: string = "Hello World";
onPageShow() {
// 注册回调函数供Native调用
testNapi.registerCallback((msg: string) => {
this.message = msg; // 更新UI
});
}
build() { /* UI布局 */ }
}
Native侧创建线程安全函数
// 定义线程安全函数结构体
struct ThreadSafeInfo {
napi_threadsafe_function tsfn;
std::string message;
};
// 创建线程安全函数
napi_value RegisterCallback(napi_env env, napi_callback_info info) {
// 获取ArkTS传递的回调函数
size_t argc = 1;
napi_value args;
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// 创建线程安全函数
napi_threadsafe_function tsfn;
napi_create_threadsafe_function(
env, args, nullptr, nullptr,
0, 1, nullptr, nullptr, nullptr,
[](napi_env env, napi_value js_cb, void* context, void* data) {
// 主线程执行回调
ThreadSafeInfo* info = static_cast<ThreadSafeInfo*>(data);
napi_value argv;
napi_create_string_utf8(env, info->message.c_str(), info->message.size(), &argv);
napi_call_function(env, nullptr, js_cb, 1, &argv, nullptr);
delete info;
}, &tsfn
);
// 存储tsfn供子线程使用
ThreadSafeInfo* threadInfo = new ThreadSafeInfo{tsfn};
napi_wrap(env, args, threadInfo, [](napi_env, void* data, void*) {
napi_release_threadsafe_function(static_cast<ThreadSafeInfo*>(data)->tsfn, napi_tsfn_release);
delete static_cast<ThreadSafeInfo*>(data);
}, nullptr, nullptr);
return nullptr;
}
子线程触发回调
// WebSocket消息接收线程
void OnMessageCallback(const char* msg) {
// 构造消息数据
ThreadSafeInfo* info = new ThreadSafeInfo;
info->message = std::string(msg);
// 向主线程投递任务
napi_call_threadsafe_function(info->tsfn, info, napi_tsfn_blocking);
}
很详细,等我明天试试,
180 都换不来你们心动吗,虽然我也不知道这积分有啥用,但是这个量已经能看出我的心切了吧[doge]
在HarmonyOS鸿蒙Next中,Native侧C++子线程无法直接调用ArkTS接口。ArkTS接口调用必须在主线程执行。可通过Native侧向ArkTS侧发送消息,由ArkTS侧在主线程处理调用。使用NAPI的异步工作线程机制,通过napi_create_async_work创建异步任务,在complete回调中触发ArkTS侧处理。需确保线程安全,避免直接跨线程访问。
目前HarmonyOS Next的Native API设计确实限制了从C++子线程直接调用ArkTS方法的能力。针对WebSocket OnMessage场景,建议采用以下替代方案:
-
使用消息队列机制:在Native侧维护一个线程安全的队列,将收到的消息存入队列。ArkTS侧通过定时轮询或事件监听方式主动拉取消息。
-
通过Native侧触发事件:利用已有的ArkTS到Native的回调机制,在Native侧保存ArkTS传递的回调方法。当OnMessage触发时,通过工作线程将消息投递到主线程,再调用预先保存的ArkTS回调。
-
使用共享内存+信号量:在Native和ArkTS间建立共享内存区域,通过信号量机制实现跨线程通信,避免直接方法调用。
这些方案虽然需要额外封装,但能有效解决当前版本的限制。建议关注后续SDK更新,官方可能会提供更直接的原生支持。