1.配置JNI环境
- 创建JNI文件夹
在项目的主目录中创建一个名为 JNI
的文件夹。这个文件夹将包含所有的本地源代码和配置文件。
- 编写Android.mk文件
这个文件是一个 Makefile,用来指导 NDK 如何编译和构建本地代码。
#清除之前定义的变量,确保每个模块的配置从干净的状态开始。
LOCAL_PATH:=$(call my-dir)#清除之前定义的变量,确保每个模块的配置从干净的状态开始。
include $(CLEAR_VARS)#定义了生成的动态链接库的名称为OBOJni,在Android系统中会自动添加前缀lib和后缀.so,成为libOBOJni.so
LOCAL_MODULE := OBOJni#指定test.cpp为此动态库的源文件。
LOCAL_SRC_FILES := test.cpp#指定链接器链接Android系统的日志库liblog,以便库中可以使用日志功能。
LOCAL_LDLIBS := -llog#引入构建系统用来编译和链接生成动态链接库的规则和命令。
include $(BUILD_SHARED_LIBRARY)
- 配置build.gradle文件:
修改项目中的 app/build.gradle
文件,在 android{}
块中添加以下配置,以指定 JNI 库文件的存储路径和指向 Android.mk
的路径:
sourceSets {main {// 设置 JNI 库的路径jniLibs.srcDirs = ['../libs']}}externalNativeBuild {ndkBuild {//表示构建androidJNI的Android.mk的所在路径path '../jni/Android.mk'}}
- 创建和编写test.cpp
#include <jni.h>
#include <android/log.h>void hello_test_jni()
{__android_log_print(ANDROID_LOG_ERROR,"JNI","hello JNI test!!!");
}
- 进入JNI路径,使用powershell编译
ndk-build.cmd
能生成 .so
文件,则表示 C++ 编译环境配置正确。
2.java调用JNI模块
- 创建JNI调用类
在 src
目录下,与 Activity 类同级,创建一个用于 JNI 调用的 Java 类 OBJNI.java
。这个类将封装所有 JNI 相关的操作:
public class OBJNI {// 单例模式确保全局只有一个实例private static OBJNI instance = null;public static OBJNI getInstance() {if (instance == null) {instance = new OBJNI();}return instance;}// 声明 native 方法public native void hello_jni();// 加载 C++ 编写的库static {System.loadLibrary("testjni"); // 库名需与 Android.mk 中的 LOCAL_MODULE 相同}
}
- 生成 native 方法的 C++ 声明:
使用 javah
工具从 OBOJNI
类生成对应的 C++ 头文件。打开命令行工具,导航至 Java 源文件所在的目录,并执行:
javah -classpath . -jni com.afison.ob.OBJNI
- 找到com_itcast_ace_obo_170325_OBOJNI.h中的对应函数声明 拷贝到 test.cpp中去实现
注意 一定要在extern C {} 中去实现 否则函数名会改变
- 重新编译cpp程序
cd C:\Users\Ace\Documents\GitHub\OBO\OBO_170325\JNI>
ndk-build.cmd
生成新的so
- 在java中 Activity中 调用此方法
OBOJNI.getInstance().hello_jni();
如果控制台能够输出cpp的日志 表示代用成功
3.报错
More than one file was found with OS independent path 'lib/arm64-v8a/libOBOJni.so'
配置packagingOptions:在你的app模块的build.gradle
文件中,使用packagingOptions
来解决冲突。你可以通过添加如下配置来告诉Gradle在打包时如何处理重复的so文件:
javah -classpath . -jni com.afison.ob.OBJNIandroid {packagingOptions {pickFirst 'lib/arm64-v8a/libOBOJni.so'// 或者使用exclude排除特定的so文件,如:// exclude 'lib/arm64-v8a/libOBOJni.so'}
}
JNI调用成功