0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙OS开发实例:【Native C++】

jf_46214456 来源:jf_46214456 作者:jf_46214456 2024-04-14 11:43 次阅读

介绍

本篇Codelab主要介绍如何使用DevEco Studio创建一个Native C++应用。应用采用Native C++模板,实现使用NAPI调用C标准库的功能。使用C标准库hypot接口计算两个给定数平方和的平方根。在输入框中输入两个数字,点击计算结果按钮显示计算后的数值。

相关概念

  • [Native API]:NAPI提供的接口名与三方Node.js一致,目前支持部分接口。
  • [Native API中支持的标准库]:目前支持标准C库、C++库、OpenSL ES、zlib。

环境搭建

软件要求

  • [DevEco Studio]版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。
  • 鸿蒙文档参考:[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]

硬件要求

  • 开发板类型:[润和RK3568开发板]。
  • OpenHarmony系统:3.2 Release。
  • 鸿蒙NEXT学习文档紫料可mau123789添加v直接领

搜狗高速浏览器截图20240326151450.png

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。以3.2 Release版本为例:
  2. 搭建烧录环境。
    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]
  3. 搭建开发环境。
    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用[真机进行调测]。

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。

使用Native C++模板创建项目会自动生成cpp文件夹、types文件夹、CMakeList.txt文件,开发者可以根据实际情况自行添加修改其他文件及文件夹。

├──entry/src/main
│  ├──common
│  │  └──CommonContants.ets               // 常量定义文件
│  ├──cpp                                 // C++代码区
│  │  ├──CMakeLists.txt                   // CMake编译配置文件
│  │  ├──hello.cpp                        // C++源代码
│  │  └──types                            // 接口存放文件夹
│  │     └──libhello
│  │        ├──index.d.ts                 // 接口文件
│  │        └──oh-package.json5           // 接口注册配置文件
│  └──ets                                 // 代码区
│     ├──entryability
│     │  └──EntryAbility.ts               // 程序入口类
│     └──pages
│        └──Index.ets                     // 主界面
└──entry/src/main/resources               // 资源文件目录

架构组成

应用架构

应用架构可以分为三部分:C++、ArkTS、工具链。

  • C++:包含各种文件的引用、C++或者C代码、Native项目必需的配置文件等。
  • ArkTS:包含界面UI、自身方法、调用引用包的方法等。
  • 工具链:包含CMake编译工具在内的系列工具。

使用ArkTS调用C++方法的过程中,需要使用到NAPI、CMake等工具来做中间转换,整个架构及其关联关系参考示意图。

示意图中,hello.cpp文件实现C++方法,并通过NAPI将C++方法与ArkTS方法关联。

C++代码通过CMake编译工具编译成动态链接库so文件,使用index.d.ts文件对外提供接口。ArkTS引入so文件后调用其中的接口。

编译架构

ArkTS与C++方法的调用、编译流程参考示意图。图中C++代码通过CMake编译生成so文件后可以直接被ArkTS侧引入,最终通过hvigor编译成可执行的hap包。

Native项目开发流程

Native侧操作详解

  1. 配置模块描述信息,设置Init方法为napi_module的入口方法。 attribute ((constructor))修饰的方法由系统自动调用,使用NAPI接口napi_module_register()传入模块描述信息进行模块注册。Native C++模板创建项目会自动生成此结代码,开发者可根据实际情况修改其中内容。

    // hello.cpp
    static napi_module demoModule = {
        nm_version = 1,
        nm_flags = 0,
        nm_filename = nullptr,
        nm_register_func = Init,         // napi_module入口方法
        nm_modname = "hello",            // napi_module模块名
        nm_priv = ((void *)0),
        reserved = { 0 }
    };
    
    extern "C" __attribute__((constructor)) void RegisterModule(void) {
        napi_module_register(&demoModule);
    }
    
  2. Init方法为Native C++模板生成的结构,开发者可根据实际情况修改其中内容。在napi_property_descriptor desc[]中,我们需要将编写的MyHypot方法与对外提供的接口myHypot接口进行关联,其他参数使用示例默认值填写。使用NAPI接口napi_define_properties构建包含方法对应列表的返回值。

    // hello.cpp
    static napi_value Init(napi_env env, napi_value exports)
    {
        if ((nullptr == env) || (nullptr == exports)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null");
            return exports;
        }
    
        napi_property_descriptor desc[] = {
            { "myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr }
        };
        if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed");
            return nullptr;
        }
        return exports;
    }
    
  3. 本例中使用C标准库的hypot方法进行计算。引入C标准库头文件math.h,使用double类型解析传入的参数后,调用C标准库方法hypot计算两数平方的和后计算平方根。使用NAPI接口napi_create_double将结果转化为napi_value类型的变量并返回。

    // hello.cpp
    #include < hilog/log.h >
    #include "napi/native_api.h"
    #include "math.h"
    
    static napi_value MyHypot(napi_env env, napi_callback_info info)
    {
        if ((nullptr == env) || (nullptr == info)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "env or exports is null");
            return nullptr;
        }
    
        // 参数数量
        size_t argc = PARAMETER_COUNT;
    
        // 定义参数数组
        napi_value args[PARAMETER_COUNT] = { nullptr };
    
        // 获取传入的参数并放入参数数组中
        if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "api_get_cb_info failed");
            return nullptr;
        }
    
        // 将传入的参数转化为double类型
        double valueX = 0.0;
        double valueY = 0.0;
        if (napi_ok != napi_get_value_double(env, args[0], &valueX) ||
            napi_ok != napi_get_value_double(env, args[1], &valueY)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_get_value_double failed");
            return nullptr;
        }
    
        // 调用C标准库的hypot接口进行计算
        double result = hypot(valueX, valueY);
    
        // 创建返回结果并返回
        napi_value napiResult;
        if (napi_ok != napi_create_double(env, result, &napiResult)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_create_double failed");
            return nullptr;
        }
        return napiResult;
    }
    
  4. 添加接口文件以及接口配置文件。接口文件index.d.ts用于对外提供方法说明。接口配置文件oh-package.json5文件中将index.d.ts与CMake编译的so文件关联起来。模块级目录下oh-package.json5文件添加so文件依赖。

    // index.d.ts
    export const myHypot: (a: number, b: number) = > number;
    
    // oh-package.json5
    {
      "name": "libhello.so",
      "types": "./index.d.ts"
    }
    
    // entry/oh-package.json5
    {
      "devDependencies": {
        "@types/libhello.so": "file:./src/main/cpp/types/libhello"
      }
    }
    
  5. 在CMakeLists.txt文件中配置CMake编译参数。配置需要添加的hello.cpp文件,编译后的so文件名为libhello.so。CMakeLists.txt是CMake编译的配置文件,里面的大部分内容无需修改,project、add_library方法中的内容可以根据实际情况修改。

    # CMakeLists.txt
    # 声明使用 CMAKE 的最小版本号
    cmake_minimum_required(VERSION 3.4.1)
    
    # 配置项目信息
    project(NativeTemplateDemo)
    
    # set命令,格式为set(key value),表示设置key的值为value
    set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
    
    # 设置头文件的搜索目录
    include_directories(
        ${NATIVERENDER_ROOT_PATH}
        ${NATIVERENDER_ROOT_PATH}/include
    )
    
    # 添加日志库
    find_library(
        # Sets the name of the path variable.
        hilog-lib
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        hilog_ndk.z
    )
    
    # 添加名为hello的库,库文件名为libhello.so
    add_library(hello SHARED hello.cpp)
    
    # 添加构建需要链接的库
    target_link_libraries(hello PUBLIC ${hilog-lib} libace_napi.z.so libc++.a)
    

    说明:

    • CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt文件所在的目录。
    • add_library:添加本地的cpp文件,多cpp文件使用空格或换行间隔。
    • target_link_libraries:添加需要链接的库,本篇Codelab使用C标准库hypot方法,此处链接libc++.a库文件。

ArkTS调用C++方法

Index.ets文件使用import语句导入CMake编译出的so文件。Button组件添加点击事件,点击按钮触发点击事件时,调用libhello.so对外提供的myHypot方法,执行计算并返回计算结果。依据结果值进行格式化,显示科学计数法或保留指定位小数。

// Index.ets
import libHello from 'libhello.so';

@Entry
@Component
struct Index {
  ...
  build() {
    ...
    Button($r('app.string.submit_button'))
      .onClick(() = > {
        let resultTemp = libHello.myHypot(this.numX, this.numY);
        if (resultTemp > CommonContants.MAX_RESULT) {
          this.result = resultTemp.toExponential(CommonContants.EXPONENTIAL_COUNT);
        } else {
          this.result = resultTemp.toFixed(CommonContants.FIXED_COUNT);
        }
      })
  }
}

界面设计

界面由标题、文本说明、计算结果展示、输入框、按钮组成。Index.ets文件完成界面实现,使用Column及Row容器组件进行布局。

// Index.ets
@Entry
@Component
struct NativeTemplate {
  ...
  build() {
    Column() {
      ...
      Column() {
        ...
        Row() {
          ...
          TextInput({ controller: this.textInputControllerX })
            .type(InputType.Number)
        }
        .height($r('app.float.tips_num_height'))
        .width(CommonContants.FULL_PARENT)
        Row() {
          ...
          TextInput({ controller: this.textInputControllerY })
            .type(InputType.Number)
            .onChange(value = > {
              this.numY = parseFloat(value);
            })
        }
        .height($r('app.float.tips_num_height'))
        .width(CommonContants.FULL_PARENT)
      }
      Row() {
        Button($r('app.string.submit_button'))
          .height(CommonContants.FULL_PARENT)
          .width($r('app.float.button_width'))
      }
      .height($r('app.float.button_height'))
      .width(CommonContants.FULL_PARENT)
    }
    .width(CommonContants.FULL_PARENT)
    .height(CommonContants.FULL_PARENT)
  }
}

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73636
  • OpenHarmony
    +关注

    关注

    25

    文章

    3718

    浏览量

    16297
  • 鸿蒙OS
    +关注

    关注

    0

    文章

    188

    浏览量

    4386
收藏 人收藏

    评论

    相关推荐

    基于OpenHarmony开发板上测试Native C++应用开发

    本文主要分享在软通动力扬帆系列“竞”OpenHarmony开发板上测试Native C++应用开发,实现eTS调用Native
    的头像 发表于 10-08 14:37 3953次阅读

    【软通动力鸿湖万联扬帆系列“竞”开发板试用体验】Native C++应用Demo示例(eTS)

    ”OpenHarmony开发板上测试Native C++应用开发,实现eTS调用Native C++
    的头像 发表于 10-13 10:19 1067次阅读
    【软通动力鸿湖万联扬帆系列“竞”<b class='flag-5'>开发</b>板试用体验】<b class='flag-5'>Native</b> <b class='flag-5'>C++</b>应用Demo示例(eTS)

    鸿蒙next开发-OpenHarmony的NDK开发

    Native API是OpenHarmony SDK上提供的一组native开发接口与工具集合(也称为NDK),方便开发者使用C或者
    的头像 发表于 01-20 11:35 1795次阅读
    <b class='flag-5'>鸿蒙</b>next<b class='flag-5'>开发</b>-OpenHarmony的NDK<b class='flag-5'>开发</b>

    鸿蒙c++模板开发详解

    鸿蒙c++模板开发详解
    发表于 09-11 15:28

    请问鸿蒙如何进行native开发

    鸿蒙如何进行native开发,类似安卓的jni,有没有相关文档
    发表于 03-29 10:21

    请问鸿蒙系统是否支持native侧opengles渲染引擎开发

    鸿蒙系统是否支持native侧opengles渲染引擎开发
    发表于 05-27 15:11

    【软通动力鸿湖万联扬帆系列“竞”开发板试用体验】试用测评报告五 –开源鸿蒙C/C++软件开发

    鸿湖万联扬帆系列“竞”开发板试用测评报告五 –开源鸿蒙C/C++软件开发大信(QQ:8125036)在成功的建立了开源
    发表于 09-22 17:29

    如何使用DevEco Studio创建Native C++应用

    应用开发环境1.1、开始前请参考应用开发快速上手链接,完成DevEco Studio的安装和开发环境配置:参考链接1.2、开发环境配置完成后,创建工程(模板选择“
    发表于 02-22 14:24

    ARM与C/OS-Ⅱ嵌入式系统设计与实例开发

    ARM与C/OS-Ⅱ嵌入式系统设计与实例开发希望大家有所收获1、掌握一种学习方法 2、学习了解嵌入式技术研发的基本概念、方法和知识 3、获得嵌入式
    发表于 04-14 14:56 34次下载

    使用React Native构建OS X桌面应用

    来自俄罗斯新西伯利亚的开发者Dima日前在GitHub上开源了一款名为React Native Desktop的开发利器,可以让开发者使用React
    发表于 10-11 09:36 0次下载
    使用React <b class='flag-5'>Native</b>构建<b class='flag-5'>OS</b> X桌面应用

    C++封装:类的作用域和实例

    C++封装:类的作用域和实例
    的头像 发表于 06-29 14:28 3565次阅读
    <b class='flag-5'>C++</b>封装:类的作用域和<b class='flag-5'>实例</b>化

    【软通动力鸿湖万联扬帆系列“竞”开发板试用体验】试用测评报告五 –开源鸿蒙C/C++软件开发

    子) 鸿湖万联扬帆系列“竞” 开发板 试用测评报告五 –  开源鸿蒙C/C++软件开发   大信(QQ:8125036)         
    的头像 发表于 10-13 10:36 1481次阅读
    【软通动力鸿湖万联扬帆系列“竞”<b class='flag-5'>开发</b>板试用体验】试用测评报告五 –开源<b class='flag-5'>鸿蒙</b><b class='flag-5'>C</b>/<b class='flag-5'>C++</b>软件<b class='flag-5'>开发</b>

    如何使用DevEco Studio创建Native C++应用

    for OpenAtom OpenHarmony (以下简称“OpenHarmony”)创建一个Native C++应用。应用采用“Native C++”模板,实现了通过Node-A
    的头像 发表于 02-21 14:30 1419次阅读

    用OpenVINO™ C++ API编写YOLOv8-Seg实例分割模型推理程序

    本文章将介绍使用 OpenVINO 2023.0 C++ API 开发YOLOv8-Seg 实例分割(Instance Segmentation)模型的 AI 推理程序。本文 C++
    的头像 发表于 06-25 16:09 1597次阅读
    用OpenVINO™ <b class='flag-5'>C++</b> API编写YOLOv8-Seg<b class='flag-5'>实例</b>分割模型推理程序

    鸿蒙开发用什么语言?

    两种开发方向 我们常说鸿蒙开发,但是其实鸿蒙开发分为两个方向: 一个是系统级别的开发,比如驱动,
    的头像 发表于 01-30 16:12 1534次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>开发</b>用什么语言?