鸿蒙NDK再探

203 阅读3分钟

书接上回,经过两篇文章的了解,相信大家已经对NDK开发有了一定认知。

做个简单小结,NDK开发打包出的SO可以分为两类:

1、纯C/C++代码编译出的so文件

2、附带中间层语言的so文件

这篇文章,将制作由鸿蒙编译出带napi层的so文件。

1、改造工程

新建native工程,cpp目录下新建如下结构的文件:

image.png

math.h

double add(double a ,double b);

math.cpp:

double add(double a ,double b){
    return a+b;
}

CMakeLists中加入头文件的编译:

cmake_minimum_required(VERSION 3.5.0)
project(NdkDemo)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

#加入头文件
include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/libmath/include)

#加入对应的源文件
add_library(entry SHARED napi_init.cpp ${NATIVERENDER_ROOT_PATH}/libmath/src/math.cpp)

target_link_libraries(entry PUBLIC libace_napi.z.so)

napi_init.cpp文件中改为引用Cpp的add方法:

#include "napi/native_api.h"
#include "libmath/include/math.h"

static napi_value Add(napi_env env, napi_callback_info info)
{
    //……
    napi_create_double(env,add(value0, value1), &sum);
    return sum;
}

尝试运行并成功看到控制台的打印结果: Test NAPI 2 + 3 = 5

2、为so库改名

默认情况下,so名为libentry,如果不改名引入多个so不就乱套了?

1.CMakeLists 修改最下面两行 entry 的文字

add_library(math SHARED napi_init.cpp)
target_link_libraries(math PUBLIC libace_napi.z.so)

2.napi_init.cpp文件中 修改 .nm_modname

static napi_module demoModule = {
    .nm_modname = "math",
};

3.修改types文件夹下的名字

image.png

4.修改libmath目录下oh-package.json5的名字

{
  "name": "libmath.so",
  "types": "./Index.d.ts",
  "version": "1.0.0",
  "description": "Please describe the basic information."
}

5.模块级oh-package.json5修改so的库名

"dependencies": {
  "libmath.so": "file:./src/main/cpp/types/libmath"
}

测试运行项目成功

3、移植新项目

原项目为 NdkDemo,新建普通工程项目 NormalDemo

1.移植so库: DdkDemo中打开build目录,找到如下文件:

image.png

entry.so为未改名前产生的so库,可以不用管他

NormalDemo中src下新建文件夹,复制libmath.so 以及 libc++shared.so ,结构如下:

image.png

2.移植导出文件和so库相关的内容 复制 NdkDemo 中的 cpp/types/libmath 文件至 NormalDemo 下。 这两个文件中保存了头文件的导出接口和so库的名称及版本信息

image.png

3.NormalDemo 中 oh-package.json5 加入依赖

"dependencies": {
  "libmath.so": "file:./src/main/cpp/types/libmath"
}

4.修改 pages/index 目录下的引用

import { add } from 'libmath.so';

//……
console.debug(`10+20=${add(10, 20)}`)

至此,测试成功

4、其他补充

1、libc++shared.so库有什么作用?

NormalDemo 中删掉该文件,测试运行,报错如下: Error message:the requested module '@normalized:Y&&&libmath.so&' does not provide an export name 'add' which imported by '&entry/src/main/ets/pages/Index&'

这是为什么呢?

鸿蒙官网给出了解释: developer.huawei.com/consumer/cn…

系统库依赖的C++标准库随镜像版本升级,而应用Native库依赖的C++标准库随编译使用的SDK版本升级。 即这个so中保存了当前应用sdk下编译所产生的一些临时文件,如引入的两个so库使用了不同版本的SDK,则需要及区分。

2、假如so由c/c++文件编译,没有napi的代码,如何处理

如上一章所示,so完全由C代码编译,此时需要把libadd.so 也放在libs/arm64-v8a目录下。其他操作相同

3、纯C文件编译的so

回到NdkDemo中,将math.cpp改为math.c ,并修改CMaklists中的math.cpp 运行项目,会出现如下错误:

//……
ld.lld: error: undefined symbol: add(double, double)
>>> referenced by napi_init.cpp:24 (C:/Users/Administrator/Desktop/NdkDemo/entry/src/main/cpp/napi_init.cpp:24)
>>>               CMakeFiles/math.dir/napi_init.cpp.o:(Add(napi_env__*, napi_callback_info__*))
>>> did you mean: extern "C" add
>>> defined in: CMakeFiles/math.dir/libmath/src/math.c.o

这里给出了提示,需要在 add方法前面加上 extern "C"

回到头文件add.h中假如即可

extern "C" 
double add(double a ,double b);