场景描述:
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, ¶m);
napi_call_function(env, sysModule, jsCb, 1, ¶m, &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
如何快速入门:
- 基本概念
- 构建第一个ArkTS应用
- ……
开发基础知识:https://qr21.cn/FV7h05
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……
基于ArkTS 开发:https://qr21.cn/FV7h05
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ……
鸿蒙开发面试真题(含参考答案):https://qr21.cn/FV7h05
大厂鸿蒙面试题::https://qr18.cn/F781PH
鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH
1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向