Android Studio 中编译 JNI 代码
经常需要实现一些 C,C++ 接口的功能模块,提供给 java 层调用。
那么就需要利用 JNI 写接口提供 java 的 native 调用。
必不可少的一步就是编译 JNI 代码。
需要的文件
- (项目)
- src
- main
- cpp
- JNI 代码(依赖)
- java
- (接口类 class)
- jniLibs
- (ANDROID_ABI)
- 依赖库文件
- (ANDROID_ABI)
- cpp
- main
- build.gradle
- CMakeLists.txt
- src
| 文件/目录 | 说明 |
|---|---|
src/main/cpp/ | 用于存放JNI源码(C、C++等),也有人喜欢更名为 jni/ |
src/main/java/ | JNI 接口的 java 调用 |
build.gradle | 配置 CMake 编译等参数 |
CMakeLists.txt | 用于设置 JNI 代码的编译方式 |
配置 build.gradle
android {
...
defaultConfig {
...
ndk {
abiFilters "armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
ndk.abiFilters 是配置编译的CPU架构,会根据架构编译出不同架构的 .so 文件。
cmake 是配置 CMake 的编译规则文件的路径,如果和 build.gradle 同级就不需要增加目录,否则按与 build.gradle 文件的路径自行配置。
添加 JNI 源码
个人习惯问题,喜欢按功能模块把 JNI 源码分类:
cpp/{功能}/include/:存放头文件
cpp/{功能}/src/:存放源代码
cpp/:存放 JNI 接口代码
这是个人习惯问题,大家可以无视。
一些 arm 架构的 so 库,建议放在 src/main/jniLibs/{ANDROID_ABI}/ 下,因为对于动态 .so 库,程序运行时需要依赖。

添加 JNI 接口
在 JNI 中,需要自行根据添加 java native 的接口位置,添加 JNI 接口。
比如我想在:src/main/java/org/xxx/yyy/zzz/faceapi/FaceApiNative.java 中添加一个名为 JniJudgeHdr 的 native 接口。
public native boolean JniJudgeHdr(byte[] bytes, int width, int height, int channels);
static {
System.loadLibrary("facehdr");
}
那么我们需要增加的 JNI 接口为:
JNIEXPORT jboolean JNICALL
Java_org_xxx_yyy_zzz_faceapi_FaceApiNative_JniJudgeHdr(
JNIEnv* env, jobject /* this */
, jbyteArray jbArr_image
, jint rows
, jint cols
, jint channels
) {
...
}
基本的文件框架为:
#include <jni.h>
#include <android/log.h>
// #include "facehdr_jni.h" // 非必要
#include "judge_hdr/include/JudgeHdr.h" // 其它依赖的头文件
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL
Java_org_xxx_yyy_zzz_faceapi_FaceApiNative_JniJudgeHdr(
JNIEnv* env, jobject /* this */
, jbyteArray jbArr_image
, jint rows
, jint cols
, jint channels
) {
...
}
#ifdef __cplusplus
}
#endif
同时如果 java 需要调用 JNI 接口,就需要设置加载对应的 JNI 库。(示例 System.loadLibrary 部分)
编译 CMake 规则
先上内容
cmake_minimum_required(VERSION 3.4.1)
# 编译后的 so 保存的位置
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
# 头文件路径
include_directories(
${CMAKE_SOURCE_DIR}/src/main/cpp
${CMAKE_SOURCE_DIR}/src/main/cpp/judge_hdr/include
)
file(GLOB FACE_HDR_SRC
${CMAKE_SOURCE_DIR}/src/main/cpp/facehdr_jni.cpp
)
add_library(
facehdr
SHARED
${FACE_HDR_SRC}
)
# 添加依赖库
add_library(judgehdr SHARED IMPORTED )
set_target_properties(judgehdr PROPERTIES
IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/src/main/${ANDROID_ABI}/libjudgehdr.so")
target_link_libraries(facehdr judgehdr)
find_library(
log-lib
log )
target_link_libraries(
facehdr
${log-lib} )
| 字段 | 说明 | 参数 |
|---|---|---|
${CMAKE_SOURCE_DIR} | 当前 CMake 规则文件的目录位置(即 CMakeLists.txt),所以其它文件的路径可以根据这个位置来设置 | |
include_directories | 使用到的头文件路径,可以包含多个路径的头文件 | |
file | 可以将多个源码文件打包(这个包命名为FACE_HDR_SRC) | |
add_library | 将源码编译为对应的库(将 ${FACE_HDR_SRC}的源码编译为 libfacehdr.so 库文件) | SHARED .so 动态库STATIC .a 静态库IMPORTED 引入外部库而不是编译生成库 |
set_target_properties | 关联需要使用的其它依赖库 | |
target_link_libraries | 把其它库一起打包到到目标库中 | |
find_library | 关联其它库(主要是 Android Studio 提供的诸如 Log 的库) |
接下来就可以运行了。
本文介绍了在Android Studio中编译JNI代码的步骤,包括准备必要的文件、配置build.gradle,添加JNI源码和接口,以及编写CMakeLists.txt规则。通过这些步骤,可以实现C/C++接口供Java层调用。
2378

被折叠的 条评论
为什么被折叠?



