开天辟地 HarmonyOS(鸿蒙) - Native Development Kit: NDK 基础

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - Native Development Kit: NDK 基础

示例如下:

pages\ndk\NdkDemo.ets

/*
 * NDK 基础
 * 详见 /ndk1/src/main/ets/pages/NdkDemo.ets
 */

import { TitleBar } from '../TitleBar';
import { common, Want } from '@kit.AbilityKit';

@Entry
@Component
struct NdkDemo {

  context = getContext() as common.UIAbilityContext;

  build() {
    Column() {
      TitleBar()

      Button("打开 ndk 演示页面").onClick(() => {
        let want: Want = {
          bundleName: 'com.webabcd.harmonydemo',
          moduleName: 'ndk1',
          abilityName: 'com.webabcd.harmonydemo.Ndk1Ability',
        };
        this.context.startAbility(want);
      })
    }
  }
}

\ndk1\src\main\ets\pages\NdkDemo.ets

/*
 * NDK - Native Development Kit
 * ABI - Application Binary Interface
 * NAPI - Node API(用于提供 ArkTS 与 c/c++ 之间的交互能力)
 *
 * 源码方式引用本地的 ndk 模块时,需要在 oh-package.json5 中做类似如下的配置
 * {
 *   "dependencies": {
 *     "libndk1.so": "file:./src/main/cpp/types/libndk1"
 *   }
 * }
 *
 * 编译 ndk 项目需要在 build-profile 中做类似如下的配置
 * {
 *   "buildOption": {
 *     "externalNativeOptions": {
 *       "path": "./src/main/cpp/CMakeLists.txt", // cmake 文件地址
 *       "abiFilters": ["arm64-v8a", "x86_64"], // 指定编译架构
 *     }
 *   },
 * }
 */

// 导入 .so
import testNapi from 'libndk1.so';
import { TitleBar } from './TitleBar';

@Entry
@Component
struct NdkDemo {
  @State message: string = 'hello ndk';

  build() {
    Column({space:10}) {
      TitleBar()

      Text(this.message)

      Button("使用 .so 计算 2 + 3").onClick(() => {
        this.message = `2 + 3 = ${testNapi.add(2, 3)}`
      })
    }
  }
}

\ndk1\src\main\cpp\napi_init.cpp

/*
 * NDK - Native Development Kit
 * ABI - Application Binary Interface
 * NAPI - Node API(用于提供 ArkTS 与 c/c++ 之间的交互能力)
 */

// 提供本地开发所需的接口和类型定义
#include "napi/native_api.h"

// 在 c/c++ 中定义一个名为 MyAdd 的函数
static napi_value MyAdd(napi_env env, napi_callback_info info)
{
    // 用于说明 MyAdd 函数的参数的个数为 2 个
    size_t argc = 2;
    // 用于定义一个长度为 2 的 napi_value 数组
    napi_value args[2] = {nullptr};
    // 将 2 个参数保存在 args 数组中
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    // 将第 1 个参数转换为 c/c++ 的 double 类型,并将此值保存在 value0 中
    double value0;
    napi_get_value_double(env, args[0], &value0);

    // 将第 2 个参数转换为 c/c++ 的 double 类型,并将此值保存在 value1 中
    double value1;
    napi_get_value_double(env, args[1], &value1);
    
    // 执行 value0 + value1 并将结果保存在 sum 中
    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

// 确保 c++ 代码以 c 链接方式编译,用于解决 c++ 和 c 之间的兼容性问题
EXTERN_C_START
// 注册导出内容
static napi_value Init(napi_env env, napi_value exports)
{
    // 将 c/c++ 的名为的 MyAdd 函数导出为 arkts 的名为 add 的函数
    napi_property_descriptor desc[] = {
        { "add", nullptr, MyAdd, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END
    
// 注册当前的 NAPI 模块
static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "ndk1",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterNdk1Module(void)
{
    napi_module_register(&demoModule);
}

\ndk1\src\main\cpp\CMakeLists.txt

# 指定构建此项目所需的 CMake 的最低版本为 3.5.0
cmake_minimum_required(VERSION 3.5.0)

# 定义项目名称
project(HarmonyDemo)

# 定义一个变量,并赋值为当前 CMake 文件所在目录
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

# 添加头文件 .h 目录,用于告诉 cmake 去这里找代码引入的头文件
include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

# 生成一个名为 ndk1 的动态链接库(比如 .so 文件),源文件为 napi_init.cpp
# 生成的 .so 文件的名称为 libndk1.so,其要与 libndk1/oh-package.json5 中的 name 一致
add_library(ndk1 SHARED napi_init.cpp)

# 将动态链接库 ndk1 链接到 libace_napi.z.so 库(libace_napi.z.so 是 OpenHarmony 的 NAPI 接口实现)
target_link_libraries(ndk1 PUBLIC libace_napi.z.so)

\ndk1\src\main\cpp\types\libndk1\Index.d.ts

// .d.ts 是类型声明文件,用于帮助 TypeScript 编译器理解 .so 中导出的函数和变量(此文件的路径是在 oh-package.json5 中的 types 标签配置的)
// 以本例来说,此处的 add 函数要与 napi_init.cpp 中的导出内容一致
export const add: (a: number, b: number) => number;

\ndk1\src\main\cpp\types\libndk1\oh-package.json5

{
  "name": "libndk1.so", // .so 的名称,要与 CMakeLists.txt 中的 add_library() 中指定的名称一致
  "types": "./Index.d.ts", // 指定类型声明文件,其用于帮助 TypeScript 编译器理解 libndk1.so 中导出的函数和变量
  "version": "1.0.0",
  "description": "Please describe the basic information."
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @   webabcd  阅读(1)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示