Android开发时经常会遇到Java调用C/C++代码,这时需要使用到JNI,下面详细介绍C/C++代码封装成JNI库。
1. 配置ndk环境
打开Andrid studio的File->Settings->Appearance & Behavior->System Settings->Android SDK的SDK Tools中下载NDK和Cmake。此时需要注意到下载地址,ndk一般在sdk的目录下的ndk文件夹中。
下图红框中能看到ndk的版本号的话,说明ndk安装成功。
2、cpp文件及so库存放位置
如下图,在app/src/main文件夹下的java同级文件夹下新建cpp文件夹,在其中存放cpp文件和h文件,也可在cpp文件夹下新建include文件夹,将.c文件和.h文件分开,.h文件全部存放在include文件夹下(下图中没有include文件夹)。
同时在java的同级路径下新建jniLibs文件夹,将java需要调用的so库放在该文件夹下,需要在CMakeList.txt中进行相应的配置。
3、在需要调用本地方法的java文件中加载so库,并声明本地函数
例如,在java文件夹下新建jnitest.java文件(名称可任意),用于声明本地函数。
public class jnitest {
static{
System.loadLibrary("jnitest");
}
public static native int addsum();
}
4、在cpp文件夹中新建c/c++文件,实现对so库中方法的调用
在cpp文件夹下新建.cpp文件,其中添加<jni.h>头文件,函数名为如下格式(包名+类名+函数名):
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_***_addsum(JNIEnv *env, jclass clazz) {
// TODO: implement addsum()
int result = addsum(1, 2);
return result;
}
此时还要添加addsum的头文件addsum.h,然后在MainActivity中实现函数调用。
5、配置CMakeList.txt文件
CmakeList.txt文件在cpp文件夹下
cmake_minimum_required(VERSION 3.4.1) #cmake版本号
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
add_library( # Sets the name of the library.
jnitest #.so库名 可自定义
SHARED
${CMAKE_SOURCE_DIR}/jnitest.cpp) #源文件所在目录,多文件的话就都加进来
#需要添加的so库,例如本用例中添加了一个cpp生成的so库libaddsum.so。
add_library(libaddsum SHARED IMPORTED)
set_target_properties(libaddsum
PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libaddsum.so)
find_library( # Sets the name of the path variable.
log-lib
log )
target_link_libraries( # Specifies the target library.
jnitest #.so库名 可自定义
libaddsum
${log-lib} )
6、配置build.gradle文件
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "***"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild{
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
ndk {
moduleName "javacallc"
ldLibs "log"
abiFilters "armeabi-v7a"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/MANIFEST.MF'
pickFirst 'lib/armeabi-v7a/libaddsum.so'
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
*** }
}