鸿蒙开发之Native API在应用工程中的使用

在HarmonyOS中,C API中的N-API接口可以实现ArkTS/TS/JS与C/C++之间的交互。N-API提供的接口名与三方Node.js一致,目前支持部分接口,支持列表见链接。

开发流程

在DevEco Studio的模板工程中包含使用N-API的默认工程,使用File->New->Create Project创建Native C++模板工程。创建后在entry/src/main目录下会包含cpp目录,可以使用N-API接口,开发C/C++代码(native侧代码)。

ArkTS/TS/JS侧通过import引入native侧的so文件,如:import hello from ‘libhello.so’,意为使用libhello.so的能力,并将名为hello的ArkTS/TS/JS对象给到应用的ArkTS/TS/JS侧,开发者可通过该对象,调用到在cpp中开发的native方法。

基本功能

N-API接口可以实现ArkTS/TS/JS和C/C++之间的交互,这里以HelloWorld工程的两个例子:

提供一个名为Add的native方法,ArkTS侧调用该方法并传入两个number,native方法将这两个number相加并返回到ArkTS侧。

提供一个名为NativeCallArkTS的native方法,ArkTS侧调用该方法并传入一个ArkTS function,native方法中调用这个ArkTS function,并将其结果返回ArkTS侧。
以此来介绍:

1.ArkTS侧如何调用到C++侧方法。
2.C++侧如何调用到ArkTS侧方法。

下面给出了工程中的:

1.entry\src\main\cpp\hello.cpp, 包含native侧逻辑。
2.entry\src\main\ets\pages\index.ets,包含ArkTS侧逻辑。
3.entry\src\main\cpp\types\libentry\index.d.ts,包含native侧暴露给ArkTS侧接口的声明。

同时给出了注解,工程中其余部分均与native默认工程相同。

// entry\src\main\cpp\hello.cpp
// 引入N-API相关头文件。
#include "napi/native_api.h"

// 开发者提供的native方法,入参有且仅有如下两个,开发者不需进行变更。
// napi_env 为当前运行的上下文。
// napi_callback_info 记录了一些信息,包括从ArkTS侧传递过来参数等。
static napi_value Add(napi_env env, napi_callback_info info)
{
    // 期望从ArkTS侧获取的参数的数量,napi_value可理解为ArkTS value在native方法中的表现形式。
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    
    // 从info中,拿到从ArkTS侧传递过来的参数,此处获取了两个ArkTS参数,即arg[0]和arg[1]。
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    // 将获取的ArkTS参数转换为native信息,此处ArkTS侧传入了两个number,这里将其转换为native侧可以操作的double类型。
    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);
    
    // native侧的业务逻辑,这里简单以两数相加为例。
    double nativeSum = value0 + value1;
    
    // 此处将native侧业务逻辑处理结果转换为ArkTS值,并返回给ArkTS。
    napi_value sum;
    napi_create_double(env, nativeSum , &sum);
    return sum;
}

static napi_value NativeCallArkTS(napi_env env, napi_callback_info info)
{
    // 期望从ArkTS侧获取的参数的数量,napi_value可理解为ArkTS value在native方法中的表现形式。
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    
    // 从info中,拿到从ArkTS侧传递过来的参数,此处获取了一个ArkTS参数,即arg[0]。
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    
    // 创建一个ArkTS number作为ArkTS function的入参。
    napi_value argv = nullptr;
    napi_create_int32(env, 10, &argv);
    
    napi_value result = nullptr;
    // native方法中调用ArkTS function,其返回值保存到result中并返到ArkTS侧。
    napi_call_function(env, nullptr, args[0], 1, &argv, &result);
    
    return result;
}

EXTERN_C_START
// Init将在exports上挂上Add/NativeCallArkTS这些native方法,此处的exports就是开发者import之后获取到的ArkTS对象。
static napi_value Init(napi_env env, napi_value exports)
{
    // 函数描述结构体,以Add为例,第三个参数"Add"为上述的native方法,
    // 第一个参数"add"为ArkTS侧对应方法的名称。
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr },
    };
    // 在exports这个ArkTS对象上,挂载native方法。
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

// 准备模块加载相关信息,将上述Init函数与本模块名等信息记录下来。
static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

// 打开so时,该函数将自动被调用,使用上述demoModule模块信息,进行模块注册相关动作。
extern "C" __attribute__((constructor)) void RegisterHelloModule(void)
{
    napi_module_register(&demoModule);
}
// entry\src\main\ets\pages\index.ets

import hilog from '@ohos.hilog';
// 通过import的方式,引入native能力。
import entry from 'libentry.so'

@Entry
@Component
struct Index {

  build() {
    Row() {
      Column() {
        // 第一个按钮,调用add方法,对应到native侧的Add方法,进行两数相加。
        Button('ArkTS call C++')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);
            hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', entry.add(2, 3));
          })
        // 第二个按钮,调用nativeCallArkTS方法,对应到native的NativeCallArkTS,在native中执行ArkTS function。
        Button('C++ call ArkTS')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);
            let ret = entry.nativeCallArkTS((value)=>{return value * 2;});
            hilog.info(0x0000, 'testTag', 'Test NAPI nativeCallArkTS ret = %{public}d', ret);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

开发建议

注册建议

nm_register_func对应的函数(如上述Init函数)需要加上static,防止与其他so里的符号冲突。
模块注册的入口,即使用__attribute__((constructor))修饰的函数的函数名(如上述RegisterHelloModule函数)需要确保不与其他模块重复。

so命名规则

so命名必须符合以下规则:

  • 每个模块对应一个so。
  • 如模块名为hello,则so的名字为libhello.so,napi_module中nm_modname字段应为hello,大小写与模块名保持一致,应用使用时写作:import hello from ‘libhello.so’。

JS对象线程限制

ArkCompiler会对JS对象线程进行保护,使用不当会引起应用crash,因此需要遵循如下原则:

  • N-API接口只能在JS线程使用。
  • env与线程绑定,不能跨线程使用。native侧JS对象只能在创建时的线程使用,即与线程所持有的env绑定。

头文件引入限制

在引入头文件时,需引入"napi/native_api.h",否则会出现N-API接口无法找到的编译报错。

怎样学习鸿蒙?

首先必学的是开发语言 ArkTS,这是重中之重,然后就是ArkUI声明式UI开发、Stage模型、网络/数据库管理、分布式应用开发、进程间通信与线程间通信技术、OpenHarmony多媒体技术……。中间还有许多的知识点,都整理成思维导图来分享给大家~
在这里插入图片描述
此外,小编精心准备了一份联合鸿蒙官方发布笔记整理收纳的《鸿蒙开发学习笔记》,内容包含ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

【有需要的小伙伴,可以扫描下方二维码免费领取!!!】

快速入门

  • 开发准备
  • 构建第一个ArkTS应用(Stage模型)
  • 构建第一个ArkTS应用(FA模型)
  • 构建第一个JS应用(FA模型)
    在这里插入图片描述

开发基础知识

  • 应用程序包基础知识
  • 应用配置文件(Stage模型)
  • 应用配置文件概述(FA模型)
    在这里插入图片描述

资源分类与访问

  • 资源分类与访问
  • 创建资源目录和资源文件
  • 资源访问
    在这里插入图片描述

学习ArkTs语言

  • 初识ArkTS语言
  • 基本语法
  • 状态管理
  • 其他状态管理
  • 渲染控制
    在这里插入图片描述

基于ArkTS声明式开发范式

  • UI开发(ArkTS声明式开发范式)概述
  • 开发布局
  • 添加组件
  • 显示图片
  • 使用动画
  • 支持交互事件
  • 性能提升的推荐方法

在这里插入图片描述

兼容JS的类Web开发范式

  • 概述
  • 框架说明
  • 构建用户界面
  • 常见组件开发指导
  • 动效开发指导
  • 自定义组件
    在这里插入图片描述

Web组件

  • 概述
  • 设置基本属性和事件
  • 并发
  • 窗口管理
  • WebGL
  • 媒体
  • 安全
  • 网络与连接
  • 电话服务
  • 数据管理

  • 在这里插入图片描述

应用模型

  • 概述
  • Stage模型开发指导
  • FA模型开发指导
    在这里插入图片描述
2024完整鸿蒙学习资料领取方式:扫描下方二维码即可~
  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值