书接上回,经过两篇文章的了解,相信大家已经对NDK开发有了一定认知。
做个简单小结,NDK开发打包出的SO可以分为两类:
1、纯C/C++代码编译出的so文件
2、附带中间层语言的so文件
这篇文章,将制作由鸿蒙编译出带napi层的so文件。
1、改造工程
新建native工程,cpp目录下新建如下结构的文件:
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文件夹下的名字
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目录,找到如下文件:
entry.so为未改名前产生的so库,可以不用管他
NormalDemo中src下新建文件夹,复制libmath.so 以及 libc++shared.so ,结构如下:
2.移植导出文件和so库相关的内容 复制 NdkDemo 中的 cpp/types/libmath 文件至 NormalDemo 下。 这两个文件中保存了头文件的导出接口和so库的名称及版本信息
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);