【鸿蒙实战开发】基于Napi调用ArkTS/系统接口

542 篇文章 5 订阅
431 篇文章 3 订阅

场景描述:

app应用在native侧调用 系统库/arkts模块的方法。

应用经常会遇到如下的业务诉求:

场景一:系统提供了ArkTS 接口,但未提供对应的NDK接口,当伙伴使用C++ 代码实现业务逻辑时,部分系统能力需要依赖系统ArkTS接口;

场景二: 系统仅提供了ArkTS 异步接口,未提供对应的NDK接口,当伙伴使用C++ 代码实现业务逻辑时,部分系统能力需要依赖系统ArkTS 异步接口;

场景三:伙伴在 TS 侧已定义接口,未实现对应的NDK接口,当伙伴使用C++ 代码实现业务逻辑时,想直接使用已有的TS 接口;

方案描述:

场景一: 系统提供了ArkTS 接口,但未提供对应的NDK接口,当伙伴使用C++ 代码实现业务逻辑时,部分系统能力需要依赖系统ArkTS接口;

例如: 获取设备的屏幕宽高。

方案:

通过napi_load_module 的方式调用系统模块接口。

核心代码

static napi_value GetDisplaySize(napi_env env, napi_callback_info info) {

  // 获取arkts侧的系统库路径

  char path[64] = "@ohos.display";

  size_t typeLen = 0;

  napi_value string;

  napi_create_string_utf8(env, path,  typeLen, &string);

  // 加载系统库

  napi_value sysModule;

  napi_load_module(env, path, &sysModule);

  // 获取系统库中的"getDefaultDisplaySync"方法

  napi_value func = nullptr;

  napi_get_named_property(env, sysModule, "getDefaultDisplaySync", &func);

  napi_value funcResult;

  napi_call_function(env, sysModule, func, 0, nullptr, &funcResult);

  napi_value widthValue = nullptr;

  napi_get_named_property(env, funcResult, "width", &widthValue);

  double width;

  napi_get_value_double(env, widthValue, &width);

  OH_LOG_INFO( LOG_APP,  "width: %{public}f", width);

  napi_value heightValue = nullptr;

  napi_get_named_property(env, funcResult, "height", &heightValue);

  double height;

  napi_get_value_double(env, heightValue, &height);

  OH_LOG_INFO(LOG_APP, "height: %{public}f", height);

  // TODO: 业务拿到width 和 height,可以进一步处理具体业务逻辑

  return nullptr;

}

运行结果:

场景二:

系统仅提供了ArkTS 异步接口,未提供对应的NDK接口,当伙伴使用C++ 代码实现业务逻辑时,部分系统能力需要依赖系统ArkTS 异步接口;

例如: 如何访问系统定义的异步ArkTS方法。

方案

通过创建线程安全函数的方式 调用系统的异步接口

核心代码: 回调到JS层

static void CallJs(napi_env env, napi_value jsCb, void *context, void *data) {

  if (env == nullptr) {

    return;

  }

  napi_value undefined = nullptr;

  napi_value promise = nullptr;

  char str[] = "wlan0";

  napi_value sysModule;

  napi_load_module(env, "@ohos.net.statistics", &sysModule);

  napi_value param;

  napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &param);

  napi_call_function(env, sysModule, jsCb, 1, &param, &promise);

  napi_value thenFunc = nullptr;

  if (napi_get_named_property(env, promise, "then", &thenFunc) != napi_ok) {

    return;

  }

  napi_value resolvedCallback;

  napi_value rejectedCallback;

  napi_create_function(env, "resolvedCallback", NAPI_AUTO_LENGTH, ResolvedCallback, data, &resolvedCallback);

  napi_create_function(env, "rejectedCallback", NAPI_AUTO_LENGTH, RejectedCallback, data, &rejectedCallback);

  napi_value argv[2] = {resolvedCallback, rejectedCallback};

  napi_call_function(env, promise, thenFunc, 2, argv, nullptr);

}

// 执行异步任务

static void ExecuteWork(napi_env env, void *data) {

  CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);

  std::promise<double> promise;

  auto future = promise.get_future();

  // 调用线程安全函数

  napi_call_threadsafe_function(callbackData->tsfn, &promise, napi_tsfn_nonblocking);

  try {

    auto result = future.get();

    OH_LOG_INFO(LOG_APP, "getIfaceRxBytes Result from JS %{public}f", result);

  } catch (const std::exception &e) {

    // OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", e.what());

  }

}

// 异步任务完成回调

static void WorkComplete(napi_env env, napi_status status, void *data) {

  CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);

  napi_release_threadsafe_function(callbackData->tsfn, napi_tsfn_release);

  napi_delete_async_work(env, callbackData->work);

  callbackData->tsfn = nullptr;

  callbackData->work = nullptr;

}

static napi_value CallAsyncFunc(napi_env env, napi_callback_info info) {

  size_t argc = 1;

  napi_value jsCb = nullptr;

  CallbackData *callbackData = nullptr;

  napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&callbackData));

  napi_value sysModule;

  napi_load_module(env, "@ohos.net.statistics", &sysModule);

  napi_value getIfaceRxBytesFunc ;

  napi_get_named_property(env, sysModule, "getIfaceRxBytes", &getIfaceRxBytesFunc);

  // 创建一个线程安全函数

  napi_value resourceName = nullptr;

  napi_create_string_utf8(env, "CallAsyncFunc", NAPI_AUTO_LENGTH, &resourceName);

  napi_create_threadsafe_function(env, getIfaceRxBytesFunc, nullptr, resourceName, 0, 1, callbackData, nullptr, callbackData, CallJs,

    &callbackData->tsfn);

  // 创建一个异步任务

  napi_create_async_work(env, nullptr, resourceName, ExecuteWork, WorkComplete, callbackData, &callbackData->work);

  // 将异步任务加入到异步队列中

  napi_queue_async_work(env, callbackData->work);

  return nullptr;

}

运行结果

场景三:

伙伴在 ArkTS/TS 侧已定义接口,当伙伴使用C++ 代码实现业务逻辑时,想直接使用已有的TS 接口;

例如: 如何调用自定义的 ArkTS/TS方法;

方案

核心代码

步骤一: ObjectUtil.ts 导出相关接口

namespace ObjectUtil {

  export function isNull(obj) {

    return obj === null;

  }

  export function isUndefined(obj) {

    return obj === undefined;

  }

  export function isNullOrUndefined(obj) {

    return isNull(obj) || isUndefined(obj);

  }

  export function toString(obj, defaultValue = '') {

    if (this.isNullOrUndefined(obj)) {

      return defaultValue;

    }

    else {

      return obj.toString();

    }

  }

}

export default ObjectUtil;

步骤二:必须在 build-profile.json5添加ets文件配置

// 必须在build-profile.json5添加配置

"arkOptions": {

  "runtimeOnly": {

    "sources": [

    './src/main/ets/common/ObjectUtil.ts',

    ],

    "packages": [

    ]

  }

},

步骤三: 在native 获取ets 模块导出的变量

/*

* 获取某个TS/JS模块导出变量

* 入参:

* path - 在工程文件夹下从ets开始的绝对路径名

* key - 待加载TS/JS模块导出变量的属性名

* 返回值:获取的TS/JS模块导出变量

*/

static napi_value GetNativeModule(napi_env env, const char *modulePath, const char *key)

{

  napi_value module;

  // 通过modulePath获取对应TS/JS模块的导出对象

  napi_load_module(env, modulePath, &module);

  napi_value outputObject = nullptr;

  // 通过对象属性名key,从导出模块变量

  napi_get_named_property(env, module, key, &outputObject );

  return outputObject ;

}

步骤四:获取方法并调用demo示例(获取/ets/common/ObjectUtil 的isNull方法,并调用isNull方法判断一个对象是否为null)

/*

* 调用系统库/ets/common/ObjectUtil模块导出方法 /ets/common/ObjectUtil 的isNull方法

* 返回值:标志是否加载成功的布尔值

*/

static napi_status CallIsNullFun(napi_env env, napi_value inputObject)

{

  const char moduleName[] = "/ets/common/ObjectUtil";

  const char funcName[] = "isNull";

  napi_value isNullFun = GetNativeModule(env, moduleName, funcName);

  

  napi_value inputArgs[1] = inputObject;

  napi_value result;

  // infoFun为"/ets/common/ObjectUtil"模块中获取的函数方法

  // inputArgs为待执行方法的入参,result为出参

  napi_call_function(env, undefined, isNullFun , 1, inputArgs, result);

  

  return result ;

}

鸿蒙全栈开发全新学习指南

之前总有很多小伙伴向我反馈说,不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以这里为大家准备了一份实用的鸿蒙(HarmonyOS NEXT)学习路线与学习文档用来跟着学习是非常有必要的。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

①全方位,更合理的学习路径
路线图包括ArkTS基础语法、鸿蒙应用APP开发、鸿蒙能力集APP开发、次开发多端部署开发、物联网开发等九大模块,六大实战项目贯穿始终,由浅入深,层层递进,深入理解鸿蒙开发原理!

②多层次,更多的鸿蒙原生应用
路线图将包含完全基于鸿蒙内核开发的应用,比如一次开发多端部署、自由流转、元服务、端云一体化等,多方位的学习内容让学生能够高效掌握鸿蒙开发,少走弯路,真正理解并应用鸿蒙的核心技术和理念。

③实战化,更贴合企业需求的技术点
学习路线图中的每一个技术点都能够紧贴企业需求,经过多次真实实践,每一个知识点、每一个项目,都是码牛课堂鸿蒙研发团队精心打磨和深度解析的成果,注重对学生的细致教学,每一步都确保学生能够真正理解和掌握。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:https://qr21.cn/FV7h05

如何快速入门:

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr21.cn/FV7h05

大厂鸿蒙面试题::https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值