第一个纯血鸿蒙应用(Napi开发-ArtTS调用C/C++)

打印 上一主题 下一主题

主题 941|帖子 941|积分 2823

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1.行业配景

纯血鸿蒙,即鸿蒙Next版已于2014年1月正式发版,鸿蒙生态设备数量已经突破10亿台,已经有凌驾15000+个应用和元服务上架。鸿蒙生态不只是移动设备这么简单,他打造的是一个1+8+n的全场景战略,真正做到了“万物互联”。近来较火的“云端一体化”计划,开发者只必要同一种开发语言写一套代码,不用关心云端部署、不用关心负载平衡、CPU、内存等性能瓶颈,将运维工作交给华为团队,且接口调用按调用次数收费,到达了“无运维、零浪费”的效果。
2.预研配景

近期公司有预研纯血鸿蒙应用层调用C/C++代码的需求,借此时机深入了解、学习鸿蒙生态。
本文会以一个《高仿Mac计算器》应用开发为案例,解说鸿蒙应用的开发流程,重点解说c++开发模块,主要讲述开发、编译、引用流程,而不是深入c/c++语法细节。
3.目的

鸿蒙开发作为一个全新的生态、要零底子看本文可能有点吃力,不外笔者只管以通俗语言来描述,另外由于篇幅限制,本文不再从零解说鸿蒙团体开发流程、ArtTS语法细节,重点解说Napi开发流程。
学习本文后能到达的效果:
1.可以从0开发一个c/c++模块,并编译天生so包
2.借助DevEco Studio可将三方so包集成至项目里
4.Napi概述

4.1.简介

Node-API是用于封装JavaScript能力为Native插件的API,独立于底层JavaScript,并作为Node.js的一部分。
4.2.支持的能力

Node-API可以去除底层的JavaScript引擎的差异,提供一套稳固的接口。
HarmonyOS的Node-API组件对Node-API的接口进行了重新实现,底层对接了ArkJS等引擎。当前支持Node-API标准库中的部分接口。
4.3.交互及场景分析

交互方式
适用场景
本文是否包罗
ArtTS直接调用C/C++
native和ArtTS源码在一块,均从零混合开发

C/C++调用ArtTS
通常用于防逆向、加大逆向难度

ArtTS调用so包间接调用C/C++
将C/C++编译为so包作为类似STL,可供甲方调用

C/C++Native层调用so包
用户C/C++有二次开发封装的场景,比方基于so包二次封装

4.4.当前支持的Node-API标准库接口


5.开发环境

5.1.开发工具

5.1.1.DevEco Studio版本

Build Version: 5.0.3.900, built on October 8, 2024
5.1.2.SDK版本

HarmonyOS NEXT Beta1 SDK, based on OpenHarmony SDK Ohos_sdk_public 5.0.0.71 (API Version 12 Release)
5.1.3.项目模子

选择stage模子
拓展:
HarmonyOS先后提供了两种应用模子


  • FA(Feature Ability)模子:HarmonyOS早期版本开始支持的模子,已经不再主推。
  • Stage模子:HarmonyOS 3.1版本开始新增的模子,是目前主推且会长期演进的模子。
5.1.4.技能栈

5.1.4.1.界面搭建

基于声明式UI-ArtUI
演变过程:JavaScript =>TypeScript => ArtTs =>ArtUI
感爱好的小伙伴可以基于演变汗青补充下营养
5.1.4.2.算法逻辑

四则运算基于c/c++语法
5.1.4.3.NDK胶水语言

NAPI作为ArtTs相互调用C/C++的粘合剂,本质上也是C/C++实现的,必要深入学习了解其api
5.1.4.4.编译工具链

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

6.1.MacOS原版计算器效果



6.2.高仿MacOS计算器效果图



6.3.Gif动图展示




7.项目结构

项目结构交复杂,本文只简明扼要的列举用到的地方,所谓“用”有两方面的意思,要么基于之前的设置进行修改,一样平常为设置文件;要么创建新文件,一样平常为开发代码文件。
7.1.so包module

  1. |─CDemo                                // 项目根目录
  2. ├──app/src/main                        // 代码区  
  3. │  │
  4. │  ├──cpp                              // C/C++代码区
  5. │  │  ├──CMakeLists.txt                // CMake编译配置文件
  6. │  │  ├──napi_init.cpp                 // napi代码
  7. │  │  ├──utils
  8. │  │  │  └──calculator.h               // C++头文件,用于函数、变量定义
  9. │  │  │  └──calculator.cpp             // C++文件,用户逻辑实现
  10. │  │  └──types                         // ArtTS层
  11. │  │     └──libapp                     // ArtTS层识别的接口存放文件夹
  12. │  │        ├──index.d.ts              // ArtTS层识别的接口文件
  13. │  │        └──oh-package.json5        // 接口注册配置文件
  14. │  ├──ets                              // ArtTS代码区
  15. │  │  ├──entryability                  // 能力包
  16. │  │  ├──EntryAbility.ets              // 程序入口类
  17. │  │  ├──pages                         // 界面包
  18. │  │  └──Index.ets                     // 主界面
  19. │  ├──resources                        // 资源文件目录
  20. │  └──module.json5                     // 模块级配置文件
  21. └──app/build-profile.json5             // 项目构建文件
复制代码
7.2.宿主module


  1. |─Calculator                           // 项目根目录
  2. ├app                                   // 代码区
  3. ├──libs                                // 本地三方库
  4. │  └──arm64-v8a                        // arm64-v8a包
  5. │  └──────libapp.so                    // arm64-v8a架构so能力包
  6. │  └──x86_64                           // x86_64包
  7. │  └──────libapp.so                    // x86_64架构so能力包
  8. ├──src/main                            // 代码区  
  9. │  └──ets                              // ArtTS代码区
  10. │     ├──entryability                  // 能力包
  11. │     │  └──EntryAbility.ets           // 程序入口类
  12. │     └──pages                         // 界面包
  13. │        └──Index.ets                  // 主界面
  14. └──────────────────resources           // 资源文件目录
  15. └──────────────────module.json5        // 模块级配置文件
复制代码
8.so包module开发步调

8.1.C/C++代码算法逻辑编写

文件放到app/src/main/cpp目录下:

  1. /**
  2. * 加法运算
  3. */
  4. double add(double param1, double param2);
  5. /**
  6. * 减法运算
  7. */
  8. double sub(double param1, double param2);
  9. /**
  10. * 乘法运算
  11. */
  12. double mul(double param1, double param2);
  13. /**
  14. * 除法运算
  15. */
  16. double div(double param1, double param2);
  17. /**
  18. * 取反运算
  19. */
  20. double oppo(double param);
复制代码

  1. #include "calculator.h"
  2. double add(double param1, double param2) {
  3.     return param1 + param2;
  4. }
  5. double sub(double param1, double param2) {
  6.     return param1 - param2;
  7. }
  8. double mul(double param1, double param2) {
  9.     return param1 * param2;
  10. }
  11. double div(double param1, double param2) {
  12.     if (param2 == 0) {
  13.         return 0;
  14.     }
  15.     return param1 / param2;
  16. }
  17. double oppo(double param) {
  18.     return -param;
  19. }
复制代码
8.2.CMake文件编写

这个文件是创建Native项目的时间主动天生的,我们一样平常环境下仅仅必要改动两个地方:
#add_library
#target_link_libraries
  1. # CMAKE 的最小版本号
  2. cmake_minimum_required(VERSION 3.5.0)
  3. # 项目名
  4. project(Calculator)
  5. # 设置编译参数
  6. set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
  7. if(DEFINED PACKAGE_FIND_FILE)
  8.     include(${PACKAGE_FIND_FILE})
  9. endif()
  10. # 指定目标include目录路径
  11. include_directories(${NATIVERENDER_ROOT_PATH}
  12.                     ${NATIVERENDER_ROOT_PATH}/include)
  13.                     
  14. # 指定C/C++源码目录路径,此路径是相对于CmakeLists.txt的路径,同时注意有多个源文件要用空格或换行符隔开
  15. add_library(app SHARED
  16.             napi_init.cpp
  17.             utils/calculator.h
  18.             utils/calculator.cpp)
  19. # 指定C/C++生成的动态链接的库名字
  20. target_link_libraries(app PUBLIC libace_napi.z.so)
复制代码
8.3.Napi代码编写


  1. // 引入Napi模块
  2. #include "napi/native_api.h"
  3. // 引入自定义头文件
  4. #include "./utils/calculator.h"
  5. /**
  6. * 获取 ArtTs层 function(double a,double b)签名函数的参数
  7. * @param env ArtTS层环境
  8. * @param info ArtTS层方法信息
  9. * @param param0 参数1地址
  10. * @param param1 参数2地址
  11. */
  12. static void getTwoDoubleParams(napi_env env, napi_callback_info info, double *param0, double *param1) {
  13.     size_t argc = 2;
  14.     napi_value args[2] = {nullptr};
  15.     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
  16.     napi_valuetype valuetype0;
  17.     napi_typeof(env, args[0], &valuetype0);
  18.     napi_valuetype valuetype1;
  19.     napi_typeof(env, args[1], &valuetype1);
  20.     double value0;
  21.     napi_get_value_double(env, args[0], &value0);
  22.     *param0 = value0;
  23.     double value1;
  24.     napi_get_value_double(env, args[1], &value1);
  25.     *param1 = value1;
  26. }
  27. /**
  28. * 加法运算翻译
  29. *
  30. * @param env
  31. * @param info
  32. * @return
  33. */
  34. static napi_value Add(napi_env env, napi_callback_info info) {
  35.     double value0 = 0, value1 = 0;
  36.     getTwoDoubleParams(env, info, &value0, &value1);
  37.     napi_value sum;
  38.     napi_create_double(env, add(value0, value1), &sum);
  39.     return sum;
  40. }
  41. /**
  42. * 减法运算翻译
  43. *
  44. * @param env
  45. * @param info
  46. * @return
  47. */
  48. static napi_value NAPI_Global_sub(napi_env env, napi_callback_info info) {
  49.     double value0 = 0, value1 = 0;
  50.     getTwoDoubleParams(env, info, &value0, &value1);
  51.     napi_value sum;
  52.     napi_create_double(env, sub(value0, value1), &sum);
  53.     return sum;
  54. }
  55. /**
  56. * 乘法运算翻译
  57. *
  58. * @param env
  59. * @param info
  60. * @return
  61. */
  62. static napi_value NAPI_Global_mul(napi_env env, napi_callback_info info) {
  63.     double value0 = 0, value1 = 0;
  64.     getTwoDoubleParams(env, info, &value0, &value1);
  65.     napi_value sum;
  66.     napi_create_double(env, mul(value0, value1), &sum);
  67.     return sum;
  68. }
  69. /**
  70. * 除法运算翻译
  71. *
  72. * @param env
  73. * @param info
  74. * @return
  75. */
  76. static napi_value NAPI_Global_div(napi_env env, napi_callback_info info) {
  77.     double value0 = 0, value1 = 0;
  78.     getTwoDoubleParams(env, info, &value0, &value1);
  79.     napi_value sum;
  80.     napi_create_double(env, div(value0, value1), &sum);
  81.     return sum;
  82. }
  83. /**
  84. * 取反运算翻译
  85. *
  86. * @param env
  87. * @param info
  88. * @return
  89. */
  90. static napi_value NAPI_Global_oppo(napi_env env, napi_callback_info info) {
  91.     size_t argc = 1;
  92.     napi_value args[1] = {nullptr};
  93.     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
  94.     napi_valuetype valuetype0;
  95.     napi_typeof(env, args[0], &valuetype0);
  96.     double value0;
  97.     napi_get_value_double(env, args[0], &value0);
  98.     napi_value sum;
  99.     napi_create_double(env, oppo(value0), &sum);
  100.     return sum;
  101. }
  102. /**
  103. * 初始化函数,用于设置模块导出的内容
  104. *
  105. * @param env
  106. * @param exports
  107. * @return
  108. */
  109. EXTERN_C_START // 宏定义,用于在 C++ 代码中标记需要以 C 语言方式编译的代码块。比extern "C"更灵活
  110. static napi_value Init(napi_env env, napi_value exports) {
  111.     // 定义要导出的属性/方法
  112.     napi_property_descriptor desc[] = {
  113.         {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
  114.         {"sub", nullptr, NAPI_Global_sub, nullptr, nullptr, nullptr, napi_default, nullptr},
  115.         {"mul", nullptr, NAPI_Global_mul, nullptr, nullptr, nullptr, napi_default, nullptr},
  116.         {"div", nullptr, NAPI_Global_div, nullptr, nullptr, nullptr, napi_default, nullptr},
  117.         {"oppo", nullptr, NAPI_Global_oppo, nullptr, nullptr, nullptr, napi_default, nullptr}};
  118.     // 将属性添加到导出对象中
  119.     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
  120.     return exports;
  121. }
  122. EXTERN_C_END
  123. /**
  124. * 定义模块结构体
  125. */
  126. static napi_module demoModule = {
  127.     .nm_version = 1,        // 模块版本号
  128.     .nm_flags = 0,         // 模块标志,默认为0
  129.     .nm_filename = nullptr, // 模块文件名,通常不需要
  130.     .nm_register_func = Init, // 注册函数,指向上面的Init函数
  131.     .nm_modname = "app",   // 模块名称,这将是JS中引入模块时使用的名称
  132.     .nm_priv = ((void *)0), // 私有数据,这里未使用
  133.     .reserved = { 0 }       // 保留字段,用于未来扩展
  134. };
  135. // 告诉编译器:"这部分代码要用 C 的方式来处理,不要用 C++ 的方式"
  136. extern "C" __attribute__((constructor)) void RegisterAppModule(void) { napi_module_register(&demoModule); }
复制代码
备注napi_property_descriptor结构体说明:
  1. typedef struct napi_property_descriptor {
  2.     const char* utf8name;         // 属性名称(UTF8字符串)
  3.     napi_value name;             // 属性名称(napi_value类型)
  4.     napi_callback method;        // 方法回调
  5.     napi_callback getter;        // getter回调
  6.     napi_callback setter;        // setter回调
  7.     napi_value value;           // 静态属性值
  8.     napi_property_attributes attributes; // 属性特性
  9.     void* data;                 // 用户数据
  10. } napi_property_descriptor;
复制代码
代码层面流程是这样的:

  • 冷启动时系统首先会主动执行#RegisterModule函数
  • #RegisterModule函数将结构体demoModule注册到 Node-API系统
  • 结构体demoModule初始化时会调用 Init函数
  • Init 函数设置模块的导出内容
  • 这样以后ArtTS就可以调用Native方法了
8.4.暴露给ArtTS接口编写

  1. export const add: (a: number, b: number) => number;
  2. export const sub: (a: number, b: number) => number;
  3. export const mul: (a: number, b: number) => number;
  4. export const div: (a: number, b: number) => number;
  5. export const oppo: (a: number) => number
复制代码
8.5.设置oh-package.json5

  1. {
  2.   // so包名称
  3.   "name": "libapp.so",
  4.   //Index.d.ts文件路径
  5.   "types": "./Index.d.ts",
  6.   "version": "1.0.0",
  7.   "description": "Please describe the basic information."
  8. }
复制代码
8.6.设置build-profile.json5

默认产出的so包仅为arm64-v8a架构,如果要支持其他架构必要设置build-profile.json5文件
  1. {
  2.   "apiType": "stageMode",
  3.   "buildOption": {
  4.     "externalNativeOptions": {
  5.       "abiFilters": ["arm64-v8a", "x86_64"],
  6.       ...
复制代码
8.7.导出so包

代码及设置文件编写完成,执行Build->Build Hap(s)/App(s)->Build Hap(s)
build完成后对应的so包会在此目录下:
  1. |─CDemo                                        // 项目根目录
  2. ├app/build/default/intermediates/libs/default  // 代码区                               // 本地三方库
  3. │  └──arm64-v8a                                // arm64-v8a包
  4. │  └──────libapp.so                            // arm64-v8a架构so能力包
  5. │  └──x86_64                                   // x86_64包
  6. │  └──────libapp.so                            // x86_64架构so能力包
复制代码
8.8.编写C/C++模块标准接口文档

此步是为了方便二次开发者开发。
9.宿主开发步调

相比于繁琐的so包开发,宿主即引用方开发起来较简单,它的工作主要在计算器界面搭建
9.1.引入so包

将libapp.so包导入到如下目录
  1. |─Calculator                           // 项目根目录
  2. ├app                                   // 代码区
  3. ├──libs                                // 本地三方库
  4. │  └──arm64-v8a                        // arm64-v8a包
  5. │  └──────libapp.so                    // arm64-v8a架构so能力包
  6. │  └──x86_64                           // x86_64包
  7. │  └──────libapp.so                    // x86_64架构so能力包
复制代码
在对应的ets文件中直接导包并调用api即可

  1. import napi from 'libapp.so';
  2. napi.add(1,2);
  3. ...
复制代码
值得注意的是:

  • import napi from 'libapp.so';当前代码会飘红,编译器无法辨认so包,但是实际上不影响编译打包运行
  • libapp.so包里的函数不会提示,如果让甲方调用发起输出标准接口文档
9.2.界面搭建及交互调用

基于ArtUI的声明式UI开发,这里只列举焦点代码:
  1. import { hilog } from '@kit.PerformanceAnalysisKit';
  2. import napi from 'libapp.so';
  3. const INPUT_MAX: number = 10
  4. const RESULT_MAX: number = 12
  5. @Entry
  6. @Component
  7. struct Index {
  8.   @State result: string = '0'
  9.   array: string[] = []
  10.   build() {
  11.     Column() {
  12.       Grid() {
  13.         GridItem() {
  14.           Text(this.result + '')
  15.             .screenTextStyle()
  16.         }.columnStart(0).columnEnd(3)
  17.         GridItem() {
  18.           Button('AC', {
  19.             type: ButtonType.Normal
  20.           })
  21.             .buttonTextStyle()
  22.             .onClick(() => {
  23.               this.result = '0'
  24.               this.array = []
  25.             })
  26.         }
  27.         GridItem() {
  28.           Button('+/-', {
  29.             type: ButtonType.Normal
  30.           })
  31.             .buttonTextStyle()
  32.             .onClick(() => {
  33.               try {
  34.                 if (this.array.length == 0) {
  35.                   return
  36.                 }
  37.                 this.result = napi.oppo(this.getNumber(this.result)).toString()
  38.                 console.info("message is" + this.getNumber(this.result))
  39.                 if (this.array.length > 0 &&
  40.                   (this.array[this.array.length-1].match(/^\d+$/) || this.array[this.array.length-1].match(/^-\d+$/))) {
  41.                   this.array[this.array.length-1] = this.result
  42.                 }
  43.               } catch (e) {
  44.                 console.error("类型转换错误!")
  45.               }
  46.             })
  47.         }
  48.         GridItem() {
  49.           Button('%', {
  50.             type: ButtonType.Normal
  51.           })
  52.             .buttonTextStyle()
  53.             .onClick(() => {
  54.               this.array.push(this.result.toString())
  55.             })
  56.         }
  57.         GridItem() {
  58.           Button('÷', {
  59.             type: ButtonType.Normal
  60.           })
  61.             .buttonTextStyle('#ffff9f0a')
  62.             .onClick(() => {
  63.               if (this.array.length == 0) {
  64.                 return
  65.               }
  66.               if (this.isSignal(this.array[this.array.length-1])) {
  67.                 this.array.pop()
  68.               }
  69.               this.array.push('÷')
  70.             })
  71.         }
  72.         GridItem() {
  73.           Button('7', {
  74.             type: ButtonType.Normal
  75.           })
  76.             .buttonTextStyle()
  77.             .backgroundColor('#ff716768')
  78.             .onClick(() => {
  79.               this.processNumber(7)
  80.             })
  81.         }
  82.         GridItem() {
  83.           Button('8', {
  84.             type: ButtonType.Normal
  85.           })
  86.             .buttonTextStyle()
  87.             .onClick(() => {
  88.               this.processNumber(8)
  89.             })
  90.         }
  91.         GridItem() {
  92.           Button('9', {
  93.             type: ButtonType.Normal
  94.           })
  95.             .buttonTextStyle()
  96.             .onClick(() => {
  97.               this.processNumber(9)
  98.             })
  99.         }
  100.         GridItem() {
  101.           Button('×', {
  102.             type: ButtonType.Normal
  103.           })
  104.             .buttonTextStyle('#ffff9f0a')
  105.             .onClick(() => {
  106.               if (this.array.length == 0) {
  107.                 return
  108.               }
  109.               if (this.isSignal(this.array[this.array.length-1])) {
  110.                 this.array.pop()
  111.               }
  112.               this.array.push('×')
  113.             })
  114.         }
  115.         GridItem() {
  116.           Button('4', {
  117.             type: ButtonType.Normal
  118.           })
  119.             .buttonTextStyle()
  120.             .onClick(() => {
  121.               this.processNumber(4)
  122.             })
  123.         }
  124.         GridItem() {
  125.           Button('5', {
  126.             type: ButtonType.Normal
  127.           })
  128.             .buttonTextStyle()
  129.             .onClick(() => {
  130.               this.processNumber(5)
  131.             })
  132.         }
  133.         GridItem() {
  134.           Button('6', {
  135.             type: ButtonType.Normal
  136.           })
  137.             .buttonTextStyle()
  138.             .onClick(() => {
  139.               this.processNumber(6)
  140.             })
  141.         }
  142.         GridItem() {
  143.           Button('-', {
  144.             type: ButtonType.Normal
  145.           })
  146.             .buttonTextStyle('#ffff9f0a')
  147.             .onClick(() => {
  148.               if (this.array.length == 0) {
  149.                 return
  150.               }
  151.               if (this.isSignal(this.array[this.array.length-1])) {
  152.                 this.array.pop()
  153.               }
  154.               this.array.push('-')
  155.             })
  156.         }
  157.         GridItem() {
  158.           Button('1', {
  159.             type: ButtonType.Normal
  160.           })
  161.             .buttonTextStyle()
  162.             .onClick(() => {
  163.               this.processNumber(1)
  164.             })
  165.         }
  166.         GridItem() {
  167.           Button('2', {
  168.             type: ButtonType.Normal
  169.           })
  170.             .buttonTextStyle()
  171.             .onClick(() => {
  172.               this.processNumber(2)
  173.             })
  174.         }
  175.         GridItem() {
  176.           Button('3', {
  177.             type: ButtonType.Normal
  178.           })
  179.             .buttonTextStyle()
  180.             .onClick(() => {
  181.               this.processNumber(3)
  182.             })
  183.         }
  184.         GridItem() {
  185.           Button('+', {
  186.             type: ButtonType.Normal
  187.           }).buttonTextStyle('#ffff9f0a')
  188.             .onClick(() => {
  189.               if (this.array.length == 0) {
  190.                 return
  191.               }
  192.               if (this.isSignal(this.array[this.array.length-1])) {
  193.                 this.array.pop()
  194.               }
  195.               this.array.push('+')
  196.             })
  197.         }
  198.         GridItem() {
  199.           Button('0', {
  200.             type: ButtonType.Normal
  201.           }).buttonTextStyle()
  202.             .onClick(() => {
  203.               this.processNumber(0)
  204.             })
  205.         }.columnStart(0).columnEnd(1)
  206.         GridItem() {
  207.           Button('.', {
  208.             type: ButtonType.Normal
  209.           }).buttonTextStyle()
  210.             .onClick(() => {
  211.               if (!this.isSignal(this.array[this.array.length-1])) {
  212.                 if (!this.array[this.array.length-1].endsWith('.')) {
  213.                   this.result = this.result + '.'
  214.                   this.array[this.array.length-1] = this.result
  215.                 }
  216.               }
  217.             })
  218.         }
  219.         GridItem() {
  220.           Button('=', {
  221.             type: ButtonType.Normal
  222.           }).buttonTextStyle('#ffff9f0a')
  223.             .onClick(() => {
  224.               this.processResult()
  225.             })
  226.         }
  227.       }
  228.       .gridStyle()
  229.       .rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
  230.       .columnsTemplate('1fr 1fr 1fr 1fr')
  231.     }.width('100%')
  232.     .height('100%')
  233.     .backgroundColor('#ff988282')
  234.     .justifyContent(FlexAlign.Center)
  235.   }
  236.   isSignal(str: string): boolean {
  237.     return str == '+' || str == '-' || str == '×' || str == '÷'
  238.   }
  239.   processResult() {
  240.     if (this.array.length != 3) {
  241.       return
  242.     }
  243.     let value = this.array[1]
  244.     if (value == '+') {
  245.       this.result = napi.add(this.getNumber(this.array[0]), this.getNumber(this.array[2])).toString()
  246.     }
  247.     if (value == '-') {
  248.       this.result = napi.sub(this.getNumber(this.array[0]), this.getNumber(this.array[2])).toString()
  249.     }
  250.     if (value == '×') {
  251.       this.result = napi.mul(this.getNumber(this.array[0]), this.getNumber(this.array[2])).toString()
  252.     }
  253.     if (value == '÷') {
  254.       this.result = napi.div(this.getNumber(this.array[0]), this.getNumber(this.array[2])).toString()
  255.     }
  256.     if (this.result.length > RESULT_MAX) {
  257.       this.array = ['0']
  258.       return
  259.     }
  260.     this.array = [this.result]
  261.   }
  262.   getNumber(str: string): number {
  263.     if (str.endsWith('.')) {
  264.       return Number(str.replace('.', ''))
  265.     }
  266.     return Number(str)
  267.   }
  268.   processNumber(n: number) {
  269.     if (this.array.length > 0) {
  270.       if (this.array[this.array.length-1].toString().length >= INPUT_MAX) {
  271.         return
  272.       }
  273.       if (this.array[this.array.length-1].toString().includes('.')) {
  274.         this.result = this.result + n
  275.         this.array[this.array.length-1] = this.result
  276.       } else if (!this.isSignal(this.array[this.array.length-1])) {
  277.         this.result = (this.getNumber(this.result) * 10 + n).toString()
  278.         this.array[this.array.length-1] = this.result
  279.       } else {
  280.         this.result = n.toString()
  281.         this.array.push(this.result.toString())
  282.       }
  283.     } else {
  284.       this.result = n.toString()
  285.       this.array.push(this.result.toString())
  286.     }
  287.   }
  288. }
  289. @Extend(Text)
  290. function screenTextStyle() {
  291.   .backgroundColor('#ff51494a')
  292.   .textAlign(TextAlign.End)
  293.   .height('100%')
  294.   .width('100%')
  295.   .fontColor("#ffe6e6e5")
  296.   .padding(10)
  297.   .borderWidth(1)
  298.   .fontSize(50)
  299.   .fontWeight(FontWeight.Normal)
  300. }
  301. @Extend(Button)
  302. function buttonTextStyle(color: string = '#ff6e6865') {
  303.   .backgroundColor(color)
  304.   .height('100%')
  305.   .width('100%')
  306.   .fontColor("#ffe6e6e5")
  307.   .padding(10)
  308.   .borderWidth(1)
  309.   .fontSize(32)
  310. }
  311. @Extend(Grid)
  312. function gridStyle() {
  313.   .width('100%')
  314.   .height(480)
  315.   .borderWidth(1)
  316.   .borderColor('#ff423e3d')
  317.   .borderRadius(10)
  318. }
复制代码
至此,ArtTS调用C/C++开发已完成。
10.应用架构

此图特意备注了文件路径,可联合章节7.1的目录结构看,方便明白,在架构层面梳理了C/C++模块、Napi、CMake工具链、ArtTs应用层之间的关系。



注意:

  • 对C库的支持请参考《Native层支持说明》章节1
  • 对C++库的支持请参考《Native层支持说明》章节2
  • 对Napi标准库的支持请参考《Native层支持说明》章节3

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小小小幸运

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表