HarmonyOS NAPI 进阶

一个关于HarmonyOS应用研发的专栏,实践中见证你的实力提升

HarmonyOS 专栏

HarmonyOS 专栏代码仓库

背景

上篇文章"HarmonyOS NAPI入门" 中,介绍了如何通过C/C++源码方式集成功能.

本篇将会介绍另外两种集成方式:

  1. NAPI源码 + 动态库(即 .so)
  2. TS接口 + 动态库(即 .so)

Native C++应用研发概况

Native C++应用场景,总结起来就如下三种

  1. HarmonyOS NAPI入门这篇文章采用的是"全部源码"方式

  2. "部分源码+动态库": 国密算法SM4已经提前被编译成了so文件,这个时候我们只需在CMakeList.txt文件中稍许配置一下,即可完成so的引用

  3. "TS接口+动态库": 国密算法SM4和NAPI接口文件均已被提前编译成了so文件,这个时候只需添加TS声明文件和配置动态库依赖

部分源码&动态库

生成SM4动态库

借助"全部源码"接入方式,先修改CMakeList.txt, 让其在编译时生成"sm4.so"文件

scss 复制代码
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(HarmonyLearn)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

add_library(customnapi SHARED main.cpp
                         util.cpp)

#源码生成 sm4.so
#add_library(sm4 SHARED sm4.cpp)

target_link_libraries(customnapi PUBLIC libace_napi.z.so sm4)

编译"entry"模块(Build -> Build Hap(s)/APP(s) -> Build Hap(s))

编译完成后的产物,可以在如下路径下找到

entry/build/default/intermediates/libs/default/

创建C++文件夹,导入文件

在entry主模块中的 "src/main" 路径下创建 "cpp" 文件夹,然后添加sm4动态库需要的透文件sm4.h,之后在"cpp"文件夹下创建一个"libs"文件夹,导入libsm4.so动态库

最终的路径

  • 头文件: scr/main/cpp/include/sm4.h
  • 动态库: scr/main/cpp/libs/arm64-v8a/libsm4.so, scr/main/cpp/libs/armeabi-v7a/libsm4.so

修改CMakeFile.txt

因为我们用到了提前编译好的libsm4.so, 所以在引入时和源码生成方式稍微不一样

差异

源码生成库

add_library(sm4 SHARED sm4.cpp)

预制库生成库

add_library(sm4 SHARED IMPORTED)

set_target_properties(sm4 PROPERTIES IMPORTED_LOCATION 路径/libsm4.so)

CMakeFile源文件

scss 复制代码
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(HarmonyLearn)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

add_library(customnapi SHARED main.cpp
                         util.cpp)

#设置 libsm4.so路径
set(my_lib_path ${CMAKE_CURRENT_SOURCE_DIR}/libs/)
message("my_lib_path = ${my_lib_path}${OHOS_ARCH}/")

#生成 sm4.so
add_library(sm4 SHARED IMPORTED)
set_target_properties(sm4 PROPERTIES IMPORTED_LOCATION ${my_lib_path}${OHOS_ARCH}/libsm4.so)

#链接customnapi动态库
target_link_libraries(customnapi PUBLIC libace_napi.z.so sm4)

配置应用Native编译选项

在"entry"模块中的build-profile.json5文件中,设置CMakeFist.txt路径和动态库CPU架构

编写NAPI接口

样例中main.cpp文件, 文件详情见代码库

ini 复制代码
// entry\src\main\cpp\main.cpp
// 引入N-API相关头文件。
#include "napi/native_api.h"
#include <csignal>
#include <iostream>
#include "sm4.h"
#include <sstream>
#include "util.h"

/**
 * 测试国密SM4接口: 加密
 *
 * @param env
 * @param info
 * @return
 */
static napi_value encryptBySm4(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    size_t typeLen = 0;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen);

    char *extContent = new char[typeLen + 1];
    napi_get_value_string_utf8(env, args[0], extContent, typeLen + 1, &typeLen);

    sm4 s;
    s.setType(sm4::CBC);
    s.setKey("1234567890123456");
    s.setIv("asdfghjklzxcvbnm");

    std::string originStr = extContent;

    std::string encryptData = s.encrypt(originStr);

    util k;
    std::string hexStr = k.strToHex(encryptData);

    const int length = hexStr.length();

    char *char_array = new char[length + 1];

    strcpy(char_array, hexStr.c_str());

    std::cout << "你好" << char_array;

    napi_value result;
    napi_create_string_utf8(env, char_array, length + 1, &result);

    delete[] char_array;

    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[] = {
       ......
{"encryptBySm4", nullptr, encryptBySm4, 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 = "customnapi",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

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

ets使用动态库

在ets文件中,通过 import customnapi from "libcustomnapi.so" 方式,即可完成引用。

开始采用国密SM4加密字符串,customnapi.encryptBySm4("测试")

至此,"NAPI源码 + 动态库" 方式已介绍完成

TS接口&动态库

这里假设我们已经准备好了动态库,假如有两个动态库:libcustomnapi.so 和 libc++_shared.so

生成动态库

关于生成动态库的过程,可参见 "生成SM4动态库" 部分

创建C++文件夹,导入TS接口文件

在entry主模块中的 "src/main" 路径下创建 "cpp/types/libcustomnapi" 文件夹.

  1. 创建动态库对外暴露的接口声明文件, index.d.ts
  2. 创建动态库与接口文件映射的配置文件,oh-package.json5

index.d.ts文件

typescript 复制代码
export const add: (a: number, b: number) => number;
export const nativeCallArkTS: (a: object) => number;
export const passStr: (a: string) => string;
export const encryptBySm4: (a: string) => string;
export const decryptBySm4: (a: string) => string;
export const generatorMockArray: (a: number) => Array<string>;
export const getCustomObject: () => Object;

oh-package.json5

json 复制代码
{
  "name": "libcustomnapi.so",
  "types": "./index.d.ts",
  "version": "",
  "description": "Please describe the basic information."
}

导入动态库

在entry主模块中创建一个"libs"文件,其路径为: entry/libs, 与 entry/src 平级

配置应用对动态库的依赖

在entry主模块中的 oh-package.json5 文件中,增加如下内容

erlang 复制代码
......
"devDependencies": {
  "libcustomnapi.so": "file:./src/main/cpp/types/libcusomnapi"
},
"dependencies": {
  "libcustomnapi.so": "file:./src/main/cpp/types/libcusomnapi"
},
......

ets使用动态库

在ets文件中,通过 import customnapi from "libcustomnapi.so" 方式,即可完成引用。

开始采用国密SM4加密字符串,customnapi.encryptBySm4("测试")

至此,"TS接口&动态库" 方式已介绍完成

结尾

关于Native C++应用的所有场景已介绍结束,如果你对这方面还想进一步实践一下,可以再研究一下 "codelabs/XComponent"中的代码,找找感觉。 样例链接:gitee.com/harmonyos/c...

如果想更进一步学习NAPI接口的使用,可参见openHarmony中的样例,其用法与HarmonyOS中的NAPI接口使用是一致的。

样例链接:gitee.com/openharmony...

关于CMakeList.txt文件的一些使用方法,可以参考 Android 的官方介绍developer.android.google.cn/studio/proj...

祝好运!

相关推荐
.生产的驴3 分钟前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw6 分钟前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
小雨cc5566ru17 分钟前
uniapp+Android智慧居家养老服务平台 0fjae微信小程序
android·微信小程序·uni-app
九圣残炎26 分钟前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis
柏箱1 小时前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css
TU^1 小时前
C语言习题~day16
c语言·前端·算法
一切皆是定数1 小时前
Android车载——VehicleHal初始化(Android 11)
android·gitee
一切皆是定数1 小时前
Android车载——VehicleHal运行流程(Android 11)
android
problc1 小时前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java