Android Studio 中编译 JNI 代码

本文介绍了在Android Studio中编译JNI代码的步骤,包括准备必要的文件、配置build.gradle,添加JNI源码和接口,以及编写CMakeLists.txt规则。通过这些步骤,可以实现C/C++接口供Java层调用。

Android Studio 中编译 JNI 代码

经常需要实现一些 C,C++ 接口的功能模块,提供给 java 层调用。

那么就需要利用 JNI 写接口提供 java 的 native 调用。

必不可少的一步就是编译 JNI 代码。

需要的文件

  • (项目)
    • src
      • main
        • cpp
          • JNI 代码(依赖)
        • java
          • (接口类 class)
        • jniLibs
          • (ANDROID_ABI)
            • 依赖库文件
    • build.gradle
    • CMakeLists.txt
文件/目录说明
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 库,程序运行时需要依赖。

示例 cpp 文件

添加 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 的库)

接下来就可以运行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值