harmony 鸿蒙安全和高效的使用N-API开发Native模块_鸿蒙native开发

return napi\_create\_reference(env, constructor, 1, &g_constructor);

};

napi_status GetConstructor(napi_env env) {
napi_value constructor;
return napi_get_reference_value(env, g_constructor, &constructor);
};


##### 使用案例2:napi\_wrap


开发者使用 napi\_wrap 接口,可以将 native 对象和 js 对象绑定,当 js 对象被 GC 回收时,需要通过回调函数对 native 对象的资源进行清理。napi\_wrap 接口本质上也是创建了一个 napi\_ref,开发者可以根据业务需要,选择由系统来管理创建的 napi\_ref,或是自行释放创建的 napi\_ref。



// 用法1:napi_wrap不需要接收创建的napi_ref,最后一个参数传递nullptr,创建的napi_ref由系统管理,不需要用户手动释放
napi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr);

// 用法2:napi_wrap需要接收创建的napi_ref,最后一个参数不为nullptr,返回的napi_ref需要用户手动释放,否则会内存泄漏
napi_ref result;
napi_wrap(env, jsobject, nativeObject, cb, nullptr, &result);
// 当jsobject和result后续不再使用时,及时调用napi_remove_wrap释放result
napi_value result1;
napi_remove_wrap(env, jsobject, result1)


### 跨语言调用开销


#### 接口调用


跨语言调用是指在一个程序中使用多种编程语言编写的代码,并且这些代码可以相互调用和交互,ArkTS 调用 C++ 就是一种跨语言调用的方式。使用 N-API 进行函数调用会引入一定的开销,因为需要进行上下文切换、参数传递、函数调用和返回值处理等,这些过程都涉及到一些性能开销。目前,通过 N-API 接口实现 ArkTS 调用 C++ 的场景大致分为三类:ArkTS 直接调用 C++ 接口、ArkTS 监听 C++ 接口以及 ArkTS 接收 C++ 回调。频繁的跨语言接口调用可能会影响业务性能,因此需要开发者合理的设计接口调用频率。


#### 数值转换


使用 N-API 进行 ArkTS 与 C++ 之间的数据转换,有如下建议: \* 减少数据转换次数:频繁的数据转换可能会导致性能下降,可以通过批量处理数据或者使用更高效的数据结构来优化性能; \* 避免不必要的数据复制:在进行数据转换时,可以使用 N-API 提供的接口来直接访问原始数据,而不是创建新的数据副本; \* 使用缓存:如果某些数据在多次转换中都会被使用到,可以考虑使用缓存来避免重复的数据转换。缓存可以减少不必要的计算,提高性能。


### 异步操作


对于IO、CPU密集型任务需要异步处理, 否则会造成主线程的阻塞。N-API 支持异步能力,允许应用程序在执行某个耗时任务时不会被阻塞,而是继续执行其他任务。当异步操作完成时,应用程序会收到通知,并可以处理异步操作的结果。


#### 异步示例


开发者可以通过如下示例将耗时任务用异步方式实现,大概逻辑包括以下三步: \* 用 napi\_create\_promise 接口创建 promise,将创建一个 deferred 对象并与 promise 一起返回,deferred 对象会绑定到已创建的 promise; \* 执行耗时任务,并将执行结果传递给 promise; \* 使用 napi\_resolve\_deferred 或 napi\_reject\_deffered 接口来 resolve 或 reject 创建的 promise,并释放 deferred 对象。



// 在executeCB、completeCB之间传递数据
struct AddonData {
napi_async_work asyncWork = nullptr;
napi_deferred deferred = nullptr;
napi_ref callback = nullptr;

double args[2] = {0};
double result = 0;

};

// 2、执行耗时任务,并将执行结果传递给 promise;
static void addExecuteCB(napi_env env, void *data) {
AddonData *addonData = (AddonData *)data;
addonData->result = addonData->args[0] + addonData->args[1];
};

// 3、使用 napi_resolve_deferred 或 napi_reject_deffered 接口来 resolve 或 reject 创建的 promise,并释放 deferred 对象;
static void addPromiseCompleteCB(napi_env env, napi_status status, void *data) {
AddonData *addonData = (AddonData *)data;
napi_value result = nullptr;
napi_create_double(env, addonData->result, &result);
napi_resolve_deferred(env, addonData->deferred, result);

if (addonData->callback != nullptr) {
    napi\_delete\_reference(env, addonData->callback);
}

// 删除异步 work
napi\_delete\_async\_work(env, addonData->asyncWork);
delete addonData;
addonData = nullptr;

};

// 1、用 napi_create_promise 接口创建 promise,将创建一个 deferred 对象并与 promise 一起返回,deferred
// 对象会绑定到已创建的 promise;
static napi_value addPromise(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];
napi_value thisArg = nullptr;
napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr);

napi_valuetype valuetype0;
napi\_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi\_typeof(env, args[1], &valuetype1);
if (valuetype0 != napi_number||valuetype1 != napi_number) {
    napi\_throw\_type\_error(env, nullptr, "Wrong arguments. 2 numbers expected.");
    return NULL;
}

napi_value promise = nullptr;
napi_deferred deferred = nullptr;
napi\_create\_promise(env, &deferred, &promise);

// 异步工作项上下文用户数据,传递到异步工作项的execute、complete之间传递数据
auto addonData = new AddonData{
    .asyncWork = nullptr,
    .deferred = deferred,
};

napi\_get\_value\_double(env, args[0], &addonData->args[0]);
napi\_get\_value\_double(env, args[1], &addonData->args[1]);

// 创建async work,创建成功后通过最后一个参数(addonData->asyncWork)返回async work的handle
napi_value resourceName = nullptr;
napi\_create\_string\_utf8(env, "addAsyncCallback", NAPI_AUTO_LENGTH, &resourceName);
napi\_create\_async\_work(env, nullptr, resourceName, addExecuteCB, addPromiseCompleteCB, (void \*)addonData,
                       &addonData->asyncWork);

// 将刚创建的async work加到队列,由底层去调度执行
napi\_queue\_async\_work(env, addonData->asyncWork);

return promise;

}


在异步操作完成后,回调函数将被调用,并将结果传递给 Promise 对象。在 JavaScript 中,可以使用 Promise 对象的 then() 方法来处理异步操作的结果。



import hilog from ‘@ohos.hilog’;
import testNapi from ‘libentry.so’

@Entry
@Component
struct TestAdd {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(“hello world”)
.onClick(() => {
let num1 = 2;
let num2 = 3;
testNapi.addPromise(num1, num2).then((result) => {
hilog.info(0x0000, ‘testTag’, ‘%{public}d’, result);
})
})
}
.width(‘100%’)
.height(‘100%’)
}
}


#### 指定异步任务调度优先级


Function Flow 编程模型(Function Flow Runtime,FFRT)是一种基于任务和数据驱动的并发编程模型,允许开发者通过任务及其依赖关系描述的方式进行应用开发。方舟 ArkTS 运行时提供了扩展 qos 信息的接口,支持传入 qos,并调用 FFRT,根据系统资源使用情况降低功耗、提升性能。


* 接口示例:napi\_status napi\_queue\_async\_work\_with\_qos(napi\_env env, napi\_async\_work work, napi\_qos\_t qos)()


	+ [in] env:调用API的环境;
	+ [in] napi\_async\_work: 异步任务;
	+ [in] napi\_qos\_t: qos 等级;
* qos 等级定义:



typedef enum {
napi_qos_background = 0,
napi_qos_utility = 1,
napi_qos_default = 2,
napi_qos_user_initiated = 3,
} napi_qos_t;

* N-API 层封装了对外的接口,对接 libuv 层 uv\_queue\_work\_with\_qos(uv\_loop\_t\* loop, uv\_work\_t\* req, uv\_work\_cb work\_cb, uv\_after\_work\_cb after\_work\_cb, uv\_qos\_t qos) 函数。
* 相较于已有接口 napi\_queue\_async\_work,增加了 qos 等级,用于控制任务调度的优先级。使用示例: “`cpp static void PromiseOnExec(napi\_env env, void \*data) { OH\_LOG\_INFO(LOG\_APP, “PromiseOnExec”); }



static void PromiseOnComplete(napi_env env, napi_status status, void *data) {
int number = *((int *)data); OH_LOG_INFO(LOG_APP, “PromiseOnComplete number = %{public}d”, number);
}

static napi_value Test(napi_env env, napi_callback_info info) {
napi_value resourceName = nullptr;
napi_create_string_utf8(env, “TestExample”, NAPI_AUTO_LENGTH, &resourceName);
napi_async_work async_work; int *data = new int(10); napi_create_async_work(env, nullptr, resourceName, PromiseOnExec, PromiseOnComplete, data, &async_work);
napi_queue_async_work_with_qos(env, async_work, napi_qos_default); return nullptr;
}


### 线程安全


如果应用需要进行大量的计算或者 IO 操作,使用并发机制可以充分利用多核 CPU 的优势,提高应用的处理效率。例如,图像处理、视频编码、数据分析等应用可以使用并发机制来提高处理速度。


虽然 N-API 本身不支持多线程并发操作,但是可以在多线程环境下进行一些数据交互,且需要格外注意线程安全。在多线程环境下,开发者可以使用 napi\_create\_threadsafe\_function 函数创建一个线程安全函数,然后在任意线程中调用。


\*\*应用场景:\*\*当 native 侧有其他线程,并且需要根据这些线程的完成结果调用 JavaScript 函数时,这些线程必须与 native 侧的主线程进行通信,才能在主线程中调用 JavaScript 函数。线程安全函数便提供了一种简化方法,避免了线程间通讯,同时可以回到主线程调用 JavaScript 函数。


#### 使用方法


##### ArkTS 侧传入回调函数



struct Index {
@State message: string = ‘Hello World’

build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
testNapi.threadSafeTest((value) => {
hilog.info(0x0000, ‘testTag’, 'js callback value = ’ + value);
})
})
}
.width(‘100%’)
}
.height(‘100%’)
}
}


##### native 侧主线程中创建线程安全函数



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

std::thread::id this_id = std::this_thread::get\_id();
OH\_LOG\_INFO(LOG_APP, "thread CallJs %{public}d.\n", this_id);
napi_status status;

status = napi\_get\_reference\_value(env, cbObj, &js_cb);

napi_valuetype valueType = napi_undefined;
napi\_typeof(env, js_cb, &valueType);
OH\_LOG\_INFO(LOG_APP, "CallJs js\_cb is napi\_function: %{public}d", valueType == napi_function);

OH\_LOG\_INFO(LOG_APP, "CallJs 0");
if (env != NULL) {
    napi_value undefined, js_the_prime;
    status = napi\_create\_int32(env, 666, &js_the_prime);
    OH\_LOG\_INFO(LOG_APP, "CallJs 1: %{public}d", status == napi_ok);
    status = napi\_get\_undefined(env, &undefined);
    OH\_LOG\_INFO(LOG_APP, "CallJs 2: %{public}d", status == napi_ok);

    napi_value ret;

    status = napi\_call\_function(env, undefined, js_cb, 1, &js_the_prime, &ret);
    OH\_LOG\_INFO(LOG_APP, "CallJs 3: %{public}d", status == napi_ok);
}

}

napi_threadsafe_function tsfn;

static napi_value ThreadSafeTest(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value js_cb, work_name;
napi_status status;

status = napi\_get\_cb\_info(env, info, &argc, &js_cb, NULL, NULL);
OH\_LOG\_INFO(LOG_APP, "ThreadSafeTest 0: %{public}d", status == napi_ok);

status = napi\_create\_reference(env, js_cb, 1, &cbObj);
OH\_LOG\_INFO(LOG_APP, "napi\_create\_reference of js\_cb to cbObj: %{public}d", status == napi_ok);

status =
    napi\_create\_string\_utf8(env, "Node-API Thread-safe Call from Async Work Item", NAPI_AUTO_LENGTH, &work_name);
OH\_LOG\_INFO(LOG_APP, "ThreadSafeTest 1: %{public}d", status == napi_ok);

std::thread::id this_id = std::this_thread::get\_id();
OH\_LOG\_INFO(LOG_APP, "thread ThreadSafeTest %{public}d.\n", this_id);

napi_valuetype valueType = napi_undefined;
napi\_typeof(env, js_cb, &valueType);
OH\_LOG\_INFO(LOG_APP, "ThreadSafeTest js\_cb is napi\_function: %{public}d", valueType == napi_function);

status = napi\_create\_threadsafe\_function(env, js_cb, NULL, work_name, 0, 1, NULL, NULL, NULL, CallJs, &tsfn);
OH\_LOG\_INFO(LOG_APP, "ThreadSafeTest 2: %{public}d", status == napi_ok);

}


##### 其他线程中调用线程安全函数



std::thread t( {
std::thread::id this_id = std::this_thread::get_id();
OH_LOG_INFO(LOG_APP, “thread0 %{public}d.\n”, this_id);
napi_status status;
status = napi_acquire_threadsafe_function(tsfn);
OH_LOG_INFO(LOG_APP, “thread1 : %{public}d”, status == napi_ok);
status = napi_call_threadsafe_function(tsfn, NULL, napi_tsfn_blocking);
OH_LOG_INFO(LOG_APP, “thread2 : %{public}d”, status == napi_ok);
});
t.detach();


#### 线程函数使用注意事项


在多线程环境下,需要避免使用共享的数据结构和全局变量,以免竞争和冲突。同时,需要确保线程之间的同步和互斥,以避免数据不一致的情况发生。除此之外,仍需注意:


* 对线程安全函数的调用是异步进行的,对 JavaScript 回调的调用将被放置在任务队列中;
* 创建 napi\_threadsafe\_function 时,可以提供 napi\_finalize 回调。当线程安全函数即将被销毁时,将在主线程上调用此 napi\_finalize 回调;
* 在调用 napi\_create\_threadsafe\_function 时给定了上下文,可以从任何调用 napi\_get\_threadafe\_function\_context 的线程中获取。


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


#### 《鸿蒙 (OpenHarmony)开发学习手册》:[`https://qr21.cn/FV7h05`]( )


**入门必看:[`https://qr21.cn/FV7h05`]( )**


1. 应用开发导读(ArkTS)
2. ……


![](https://img-blog.csdnimg.cn/img_convert/4991b6612f7848b8226a785e9bf2fbe9.webp?x-oss-process=image/format,png)


**HarmonyOS 概念:[`https://qr21.cn/FV7h05`]( )**


1. 系统定义
2. 技术架构
3. 技术特性
4. 系统安全


![](https://img-blog.csdnimg.cn/img_convert/53c5d7c674e3b2bf227cbf917fccef69.webp?x-oss-process=image/format,png)


**如何快速入门:[`https://qr21.cn/FV7h05`]( )**


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


![](https://img-blog.csdnimg.cn/img_convert/52d468782ba786e32203d4ea7c7afc2b.webp?x-oss-process=image/format,png)


**开发基础知识:[`https://qr21.cn/FV7h05`]( )**


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


![](https://img-blog.csdnimg.cn/img_convert/2e9f9af56c68d6b543f76207bccf7bab.webp?x-oss-process=image/format,png)


**基于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://img-blog.csdnimg.cn/img_convert/1a53a915fa49ea95ad0f0ffa72873a8c.webp?x-oss-process=image/format,png)


### 总结


鸿蒙系统开发作为当下的一个风口,对于有志于投身技术领域的小白来说是一个难得的机遇。通过深入了解鸿蒙系统的技术优势和市场前景,你将能够做出明智的选择。记住,站在风口上,猪都能飞起来,而掌握鸿蒙开发技能,或许就是你起飞的翅膀。现在就开始行动吧!


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


#### 《鸿蒙 (OpenHarmony)开发学习手册》:[`https://qr21.cn/FV7h05`]( )


**入门必看:[`https://qr21.cn/FV7h05`]( )**


1. 应用开发导读(ArkTS)
2. ……


![](https://img-blog.csdnimg.cn/img_convert/4991b6612f7848b8226a785e9bf2fbe9.webp?x-oss-process=image/format,png)


**HarmonyOS 概念:[`https://qr21.cn/FV7h05`]( )**




还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!


王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。


对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!


【完整版领取方式在文末!!】


***93道网络安全面试题***


![](https://img-blog.csdnimg.cn/img_convert/6679c89ccd849f9504c48bb02882ef8d.png)








![](https://img-blog.csdnimg.cn/img_convert/07ce1a919614bde78921fb2f8ddf0c2f.png)





![](https://img-blog.csdnimg.cn/img_convert/44238619c3ba2d672b5b8dc4a529b01d.png)





内容实在太多,不一一截图了


### 黑客学习资源推荐


最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!


对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。


😝朋友们如果有需要的话,可以联系领取~

#### 1️⃣零基础入门


##### ① 学习路线


对于从来没有接触过网络安全的同学,我们帮你准备了详细的**学习成长路线图**。可以说是**最科学最系统的学习路线**,大家跟着这个大的方向学习准没问题。


![image](https://img-blog.csdnimg.cn/img_convert/acb3c4714e29498573a58a3c79c775da.gif#pic_center)


##### ② 路线对应学习视频


同时每个成长路线对应的板块都有配套的视频提供:


![image-20231025112050764](https://img-blog.csdnimg.cn/874ad4fd3dbe4f6bb3bff17885655014.png#pic_center)


#### 2️⃣视频配套工具&国内外网安书籍、文档


##### ① 工具


![](https://img-blog.csdnimg.cn/img_convert/d3f08d9a26927e48b1332a38401b3369.png#pic_center)


##### ② 视频


![image1](https://img-blog.csdnimg.cn/img_convert/f18acc028dc224b7ace77f2e260ba222.png#pic_center)


##### ③ 书籍


![image2](https://img-blog.csdnimg.cn/img_convert/769b7e13b39771b3a6e4397753dab12e.png#pic_center)

资源较为敏感,未展示全面,需要的最下面获取

![在这里插入图片描述](https://img-blog.csdnimg.cn/e4f9ac066e8c485f8407a99619f9c5b5.png#pic_center)![在这里插入图片描述](https://img-blog.csdnimg.cn/111f5462e7df433b981dc2430bb9ad39.png#pic_center)


##### ② 简历模板


![在这里插入图片描述](https://img-blog.csdnimg.cn/504b8be96bfa4dfb8befc2af49aabfa2.png#pic_center)

 **因篇幅有限,资料较为敏感仅展示部分资料,添加上方即可获取👆**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/topics/618540462)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值