JNI,即Java Native Interface
参考JNI规范
Android Studio集成了NDK开发工具用于JNI开发,环境配置参考NDK配置及基本语法
Java类中声明本地方法
public native String stringFromJNI();
生成.h头文件
- 进入java源码根目录,如MyNative\app\src\main\java
- 对.java文件使用javah命令,如:
javah demo.mynative.MainActivity
查看Java类中字段和方法的签名
- 进入Java类所在目录,如MyNative\app\build\intermediates\classes\debug\demo\mynative
- 对.class文件使用javap命令,如:
javap -p -s MainActivity.class
.cpp文件中实现本地方法
#include <jni.h>
#include <string>
#include <android/log.h>
extern "C"
#define LOG_TAG "native-lib"
JNIEXPORT jstring JNICALL Java_whoisblue_mynative_MainActivity_stringFromJNI(JNIEnv *env, jobject obj) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "stringFromJNI");
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
本地代码调用Java方法和字段
Java方法如:
public int count = 0;
public boolean onNativeCalled(int i) {
Toast.makeText(this, "onNativeCalled " + i, Toast.LENGTH_SHORT).show();
return true;
}
本地代码如:
#include <jni.h>
#include <string>
#include <android/log.h>
extern "C"
#define LOG_TAG "native-lib"
JNIEXPORT jstring JNICALL Java_whoisblue_mynative_MainActivity_stringFromJNI(JNIEnv *env, jobject obj) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "stringFromJNI");
jclass cls = env->GetObjectClass(obj);
jfieldID countId = env->GetFieldID(cls, "count", "I");
env->SetIntField(obj, countId, 123);
jint count = env->GetIntField(obj, countId);
jmethodID methodId = env->GetMethodID(cls, "onNativeCalled", "(I)Z");
env->CallBooleanMethod(obj, methodId, count);
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
动态注册本地方法
区别于上文的静态注册方式,即本地方法名遵循“Java_包名_类名_方法名”的格式以对应Java类中声明的方法。
另一种注册方式可通过JNI_OnLoad方法对本地方法名进行注册,本地方法名可自由格式。
Java类中声明本地方法:
public native int intFromJNI();
.cpp文件中实现方法,并动态注册:
#include <jni.h>
#include <string>
#include <android/log.h>
extern "C"
#define LOG_TAG "native-lib"
static jint JNICALL getInt(JNIEnv *env, jobject obj) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "getInt");
return 123456;
}
static const JNINativeMethod gMethods[] = {
{"intFromJNI", "()I", (jint*)getInt}
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "JNI_OnLoad");
JNIEnv* env;
if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
if(env->RegisterNatives(env->FindClass("whoisblue/mynative/MainActivity"), gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
env->FatalError("RegisterNatives failed");
}
return JNI_VERSION_1_6;
}