HarmonyOS NEXT应用开辟之NAPI封装ArkTS接口案例_harmonyos napi(1)

[复制链接]
发表于 2026-2-27 03:21:57 | 显示全部楼层 |阅读模式
先容

部分应用的紧张开辟语言为C/C++,但是HarmonyOS的部分接口仅以ArkTS的情势袒露,因此须要将ArkTS的接口封装为Native接口。本例以DocumentViewPicker的Select方法为例,提供了Napi封装ArkTS API的通用方法,本例包罗内容如下:

  • Native侧与ArkTS侧的相互调用
  • Native对象转换为ArkTS对象(包罗如安在ArkTS侧调用一样平常情势的Native方法)
  • 线程安全函数的使用
  • 等候线程安全函数的实验效果
  • 多实例情况下,如安在准确的窗口内实验方法
效果图预览


测试分析

  • 点击"JS线程调用"按钮,从native侧js线程拉起picker
  • 点击"Thread线程调用"按钮,从native侧pthread子线程中拉起picker
  • 拉起picker后,单击直接选择单个文件,长按可选择多个文件
  • 本例在拉起picker时设置了maxSelectNumber=3,最多个选择3个文件
集身分析

  • 源码集成
  • 参考aki方式集成
使用分析

  • [发起]在EntryAbility之外调用registryDocumentViewPickerFn方法,克制多实例下的重复注册
  • [必须]给每个UIAbility天生唯一的ID属性,可使用generateAbilityID方法
  • [必须]在UIAbility的onWindowStageCreate中的windowStage.loadContent的回调中调用addUIContext方法
  • [必须]在UIAbility的onWindowStageCreate中的windowStage.loadContent之后调用setTopAbilityID
  • [发起]在UIAbility的onWindowStageDestroy中调用removeUIContext方法
实现思绪


  • native侧须要自动调用ets侧的代码,须要将ets侧代码注入到native侧,并在注册时创建函数的引用及线程安全函数,并生存当火线程(js线程)的id及env供后续调用时使用
ets侧:
etswrapper.registryDocumentViewPickerFn(documentViewPickerSelect, documentViewPickerSave);
native侧:
NODE_API_CALL(env, napi_create_threadsafe_function(env, args[0], nullptr, selectWork, 0, 1, nullptr, nullptr,
nullptr, tsfn::callJSSelect, &(uniContext->selectTsfn)));
NODE_API_CALL(env, napi_create_threadsafe_function(env, args[1], nullptr, saveWork, 0, 1, nullptr, nullptr,
nullptr, tsfn::callJSSave, &(uniContext->saveTsfn)));
NODE_API_CALL(env, napi_create_reference(env, args[0], 1, &(uniContext->selectRef)));
NODE_API_CALL(env, napi_create_reference(env, args[1], 1, &(uniContext->saveRef)));
uniContext->pickerEnv = env;
uniContext->jsThreadID = fns::getCurrentThreadID();

  • 对于某些有返回值的ets函数,为了获取其返回值,须要对调用线程举行区分:如果是js线程,直接通过napi_call_function发起调用并得到返回值;否则须要等异步线程实验完毕并通过全局变量获取效果然后返回
if (uniContext->jsThreadID != fns::getCurrentThreadID()) {
status = napi_acquire_threadsafe_function(uniContext->selectTsfn);
status = napi_call_threadsafe_function(uniContext->selectTsfn, selectParam, napi_tsfn_blocking);
std::unique_lockstd::mutex unil(uniContext->resultWaitUtil.lock);
uniContext->resultWaitUtil.cv.wait(unil, [] { return uniContext->resultWaitUtil.isFinished; });
return;
} else {
status = napi_call_function(uniContext->pickerEnv, nullptr, tsSelect, 4, args, &result);
}

  • 由于napi中的线程安全函数只能通过napi_threadsafe_function_call_js中的data参数举行传参,因此须要将所需参数全部封装到一个对象中
DocumentViewPickerSelectParam *selectParam = new DocumentViewPickerSelectParam(options, thenWrapper, catchWrapper)

  • 由于本例中的filepicker是异步的,回调函数须要调用者传入,而napi中若须要将native方法直接封装为ets方法对于函数范例是有要求的。因此这里通过将回调函数封装到对象中,通过对象包装来实现将一样平常范例的函数封装为ets侧的函数:
native侧:
// step:范例声明
class DocumentViewPickerSelectThenCbWrapper {
public:
documentSelectThenFn thenFn;
DocumentViewPickerSelectThenCbWrapper(documentSelectThenFn fn) : thenFn(fn) {}
/**


  • 将对象实例包装为js对象
    /
    napi_value convert2NapiValue(napi_env env);
    /
    *
  • 参数是string[],这内里会调用thenFn,ets侧调用
    */
    static napi_value call(napi_env env, napi_callback_info info);
    };
    // step2:convert2NapiValue方法实现
    napi_value etswrapper:ocumentViewPickerSelectThenCbWrapper::convert2NapiValue(napi_env env) {
    napi_value object;
    DocumentViewPickerSelectThenCbWrapper *thenWrapper = new DocumentViewPickerSelectThenCbWrapper(this->thenFn);
    NODE_API_CALL(env, napi_create_object(env, &object));
    NODE_API_CALL(env, napi_wrap(
    env, object, thenWrapper,
    [](napi_env env, void *finalize_data, void *finalize_hint) -> void {
    delete reinterpret_cast<DocumentViewPickerSelectThenCbWrapper *>(finalize_data);
    },
    nullptr, nullptr));
    napi_property_descriptor desc[] = {
    {“call”, nullptr, DocumentViewPickerSelectThenCbWrapper::call, nullptr, nullptr, nullptr, napi_default,
    nullptr},
    };
    NODE_API_CALL(env, napi_define_properties(env, object, sizeof(desc) / sizeof(*desc), desc));
    return object;
    }
    // step3:call方法实现
    napi_value etswrapper:ocumentViewPickerSelectThenCbWrapper::call(napi_env env, napi_callback_info info) {
    // …
    napi_value thisArg;
    NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));
    DocumentViewPickerSelectThenCbWrapper *thenWrapper;
    NODE_API_CALL(env, napi_unwrap(env, thisArg, reinterpret_cast<void **>(&thenWrapper)));
    // …
    thenWrapper->thenFn(data);
    return nullptr;
    }
ets侧:
function documentViewPickerSelect(uiContext: UIContext, options: picker.DocumentSelectOptions, thenWrapper:
StringArrayThenCbWrapper, catchWrapper: CatchCbWrapper): void {
let documentViewPicker: picker.DocumentViewPicker = new picker.DocumentViewPicker();
documentViewPicker.select(options).then((value: string[]) => {
thenWrapper.call(value);
}).catch((error: BusinessError) => {
// …
自我先容一下,小编13年上海交大结业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里不绝到如今。
深知大多数HarmonyOS鸿蒙开辟工程师,想要提拔技能,通常是本身探索发展大概是报班学习,但对于培训机构动则几千的学费,着实压力不小。本身不成体系的自学效果低效又漫长,而且极易遇到天花板技能故步自封!
因此网络整理了一份《2024年HarmonyOS鸿蒙开辟全套学习资料》,初志也很简单,就是渴望可以大概资助到想自学提拔又不知道该从何学起的朋侪,同时减轻各人的负担。



既有恰当小白学习的零根本资料,也有恰当3年以上履历的小同伴深入学习提拔的进阶课程,根本涵盖了95%以上HarmonyOS鸿蒙开辟知识点,真正体系化!
由于文件比力大,这里只是将部分目次大纲截图出来,每个节点内里都包罗大厂面经、学习条记、源码课本、实战项目、解说视频,而且会连续更新
如果你以为这些内容对你有资助,可以添加VX:vip204888 (备注鸿蒙获取)

一个人可以走的很快,但一群人才华走的更远。岂论你是正从事IT行业的老鸟或是对IT行业感爱好的新人,都接待扫码到场我们的的圈子(技能交换、学习资源、职场吐槽、大厂内推、口试辅导),让我们一起学习发展!
你以为这些内容对你有资助,可以添加VX:vip204888 (备注鸿蒙获取)**
[外链图片转存中…(img-Jd7kgove-1712663975315)]
一个人可以走的很快,但一群人才华走的更远。岂论你是正从事IT行业的老鸟或是对IT行业感爱好的新人,都接待扫码到场我们的的圈子(技能交换、学习资源、职场吐槽、大厂内推、口试辅导),让我们一起学习发展!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表