概述
jni 是java native interface简称,是Java在C或C++的实现接口,共存在Java的类中。所以在jni里注册的是Java的类。不过以“/”代替Java的“.”.
JNI_OnLoad 方法
/*************native jniTestClass.cpp******************************/
#include "jni.h"
#include "JNIHelp.h"
static const char *classPathName = "android/com/test/testClass";
static JNINativeMethod methods[ ] = {
{ "nativeTest", "(ILandroid/os/Parcel;Ljava/lang/Object;)I", (void *)android_com_test_testClass_nativeTest },
};
/*
* Register several Native methods for one class.
*/
static int registerNativeMethods(JNIEnv *env, const char *className,
JNINativeMethod *gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
ALOGE("Native registration unable to find class '%s'", className);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
ALOGE("RegisterNatives failed for '%s'", className);
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Register Native methods for all classes we know about.
*
* returns JNI_TRUE on success.
*/
static int registerNatives(JNIEnv *env)
{
if (!registerNativeMethods(env, classPathName,
methods, sizeof(methods) / sizeof(methods[0]))) {
return JNI_FALSE;
}
return JNI_TRUE;
}
// ----------------------------------------------------------------------------
/*
* This is called by the VM when the shared library is first loaded.
*/
typedef union
{
JNIEnv *env;
void *venv;
} UnionJNIEnvToVoid;
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
jint result = -1;
JNIEnv *env = NULL;
ALOGI("JNI_OnLoad");
if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed");
goto bail;
}
env = uenv.env;
if (registerNatives(env) != JNI_TRUE) {
ALOGE("ERROR: registerNatives failed");
goto bail;
}
result = JNI_VERSION_1_4;
bail:
return result;
}
Jni Java 对应方法
/*************javaTestClass.java******************************/
packageandroid.com.test;
import android.util.Log;
import android.os.Parcel;
import android.os.Parcelable;
public class TestClass{
private
final static String TAG = "TestClass";
private
int mNativeContext; // native context
public
native final int nativeTest(int dataType, Parcel objParcel, Object objDvbEit);/*******与 jniTestClass.cppmethods 对应*********/
static
{
// the name supplied to loadLibrary.
Log.i(TAG, "load testjni lib");
System.loadLibrary("testjni"); /*****调用JNI_OnLoad的方法******/
}
public TestClass()
{
nativeTest(0,null,null);/*****调用android_com_test_testClass_nativeTest******/
}
}
JNINativeMethod 类型定义
Java 和 C 函数的映射表数组,并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod,定义如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。
其中比较难以理解的是第二个参数,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
具体的每一个字符的对应关系如下
字符 Java类型 C类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
数组则以"["开始,用两个字符表示
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring
Ljava/lang/String; String jstring
Ljava/net/Socket; Socket jobject
如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。
例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"