鸿蒙NEXT开发【ts回调接口实现分布】

1.ts接口申明

index.d.ts

export const startDownload: (cbFn: (progress: number) => void) => void;

2. C/C++ 代码

typedef struct CallbackContext {
    napi_env env = nullptr;
    napi_ref callbackRef = nullptr;
    int progress = 0;
} CallbackContext;

// Call back the ts side function to notify the progress information to the ts side.
static void callTS(napi_env env, napi_value jsCb, void *context, void *data) {
    CallbackContext *arg = (CallbackContext *)data;
    napi_value progress;
    //使用CallbackContext中的数据,构造progress
    napi_create_int32(arg->env, arg->progress, &progress);
    //调用jsCb,参数为progress,1位参数个数
    napi_call_function(arg->env, nullptr, jsCb, 1, &progress, nullptr);
}

// Simulate a download task. Because the ts side function is called here, a thread-safe function must be used.
void downloadTask(CallbackContext *context) {
    if (context) {
        napi_value workName;
        napi_create_string_utf8(context->env, "download", NAPI_AUTO_LENGTH, &workName);
        napi_value jsCb;
        //获取回调对象,保存在jsCb中
        napi_get_reference_value(context->env, context->callbackRef, &jsCb);
        napi_threadsafe_function tsFn;
        //创建tsFn,看起来jsCb无法直接使用。注意callTS有一个函数指针
        napi_create_threadsafe_function(context->env, jsCb, nullptr, workName, 0, 1, nullptr, nullptr, nullptr, callTS, &tsFn);
        int progressLength = 100;
        while (context->progress < progressLength) {
            context->progress += 1;
            //napi调用tsFn函数,转到callTS函数
            napi_acquire_threadsafe_function(tsFn);
            napi_call_threadsafe_function(tsFn, (void *)context, napi_tsfn_blocking);
            std::this_thread::sleep_for(std::chrono::milliseconds(progressLength));
        }
    } else {
        return;
    }
    napi_delete_reference(context->env, context->callbackRef);
    delete context;
};

static napi_value startDownload(napi_env env, napi_callback_info info) {
    //step 1: ts到达c/C++代码逻辑框架
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    //info由ts模块经napi框架传递到这里,里面包含了回调函数的信息
    //只有一个回调函数,因此argc为1,args在这里被info中的值初始化
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    //构造一个CallbackContext,并与当前env绑定
    auto asyncContext = new CallbackContext();
    asyncContext->env = env;
    //用args的值构造asyncContext的callbackRef,看起来c/C++通过callbackRef来完成后面的回调
    napi_create_reference(env, args[0], 1, &asyncContext->callbackRef);
    /*
     * Start the download thread, perform the download task in the child thread and notify the progress to the arkTs
     * thread in real time.
     */
    //启动线程,在线程中使用回调接口
    std::thread downloadThread(downloadTask, asyncContext);
    downloadThread.detach();
    //ts的接口调用,在这里完成调用。
    return nullptr;
}


//startDownload回调函数组册
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"startDownload", nullptr, startDownload, 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 callbackModule = {
    .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(&callbackModule); }

desc[]数组定义了回调函数数组,这里只定义了一个回调函数;可以看到在在C/C++中实现了回调函数并不是以func定义,是定义为properties。napi_property_descriptor一个proterty的结构体,暂时还没有深究该结构体的内容;这里主要关注第一个字符串参数,需要与ts中申明的接口字符串一致。第三个函数指针参数指向一个C++的函数startDownload,倒数第二个参数定义了这个属性在napi框架中napi_property_attributes,可以参数该结构体的信息如下:

typedef enum {
  napi_default = 0,
  napi_writable = 1 << 0,
  napi_enumerable = 1 << 1,
  napi_configurable = 1 << 2,

  // Used with napi_define_class to distinguish static properties
  // from instance properties. Ignored by napi_define_properties.
  napi_static = 1 << 10,

#if NAPI_VERSION >= 8
  // Default for class methods.
  napi_default_method = napi_writable | napi_configurable,

  // Default for object properties, like in JS obj[prop].
  napi_default_jsproperty = napi_writable |
                            napi_enumerable |
                            napi_configurable,
#endif  // NAPI_VERSION >= 8
} napi_property_attributes;

通过以上代码,实现ts注册C/C++回调,并在c/C++中使用回调关键点包含以下信息:

1. napi_define_properties接口,注册napi_property_descriptor数组,napi_property_descriptor包含proterty,里面包含提供给ts的回调函数注册接口

  1. C/C++ 模块拿到ts模块传过来的回调接口,需要将接口转换为C/C++可以使用的回调主要步骤包含如下
  • napi_callback_info为ts传递过来的结构信息,需要使用napi_get_cb_info获取内部的回调接口,保存为napi_value类型,
    
  • 由于回调不是立刻使用需要在合适的时候使用,这里将napi_value类型的回调使用napi_create_reference函数保存为一个napi_ref,在需要使用时,使用napi_get_reference_value函数获取napi_value;
  • 因为回调可能是异步的,为了确保线程安全性,使用了特别的napi_create_threadsafe_function,创建了一个线程安全的环境,在专门的线程中处理回调。配合的线程安全的函数有napi_acquire_threadsafe_function,napi_call_threadsafe_function。
  • 最后使用napi_call_function(arg->env, nullptr, jsCb, 1, &progress, nullptr);完成回调,jsCb为napi_value类型,progress为napi_value
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值