android jni的坑

原创内容,转载请注明出处

Posted by Weakyon Blog on January 27, 2015

传统的jni方式是这个步骤

1.在java文件中定义native函数

2.使用javah 生成对应C函数定义并实现

3.编写Android.mk把C源码用ndk编译成动态库

4.在java中调入编译好的动态库

然而android下是不行的,android下的jni必须要有JNI_OnLoad函数

  
#define JNIREG_CLASS "com/hello/helloworld"//指定要注册的类

#define TAG "HELLOWORLD-JNI"

static JNINativeMethod gMethods[] = {
	{ "hello_world", "([BJ[BJ)[B", (void*)Java_com_hello_hello_world },//绑定
};

static int registerNativeMethods(JNIEnv* env, const char* className,
		JNINativeMethod* gMethods, int numMethods)
{
	jclass clazz;
	clazz = (*env)->FindClass(env, className);
	if (clazz == NULL) {
		__android_log_print(ANDROID_LOG_ERROR, TAG, "Native registration unable to find class '%s'\n", className);
		return JNI_FALSE;
	}
	if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
		__android_log_print(ANDROID_LOG_ERROR, TAG, "RegisterNatives failed for '%s'\n", className);
		return JNI_FALSE;
	}

	return JNI_TRUE;
}


static int registerNatives(JNIEnv* env)
{
	if (!registerNativeMethods(env, JNIREG_CLASS, gMethods, 
				sizeof(gMethods) / sizeof(gMethods[0])))
		return JNI_FALSE;

	__android_log_print(ANDROID_LOG_INFO, TAG, "Load success!");
	return JNI_TRUE;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
	JNIEnv* env = NULL;
	jint result = -1;

	if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		__android_log_print(ANDROID_LOG_ERROR, TAG, "GetEnv failed!");
		return -1;
	}
	if(env == NULL){
		__android_log_print(ANDROID_LOG_ERROR, TAG, "GetEnv failed!");
		return -1;
	}

	__android_log_print(ANDROID_LOG_INFO, TAG, "Loading . . .");

	if (!registerNatives(env)) {//注册
		return -1;
	}
	/* success -- return valid version number */
	result = JNI_VERSION_1_4;

	return result;
}

关于JNINativeMethod的说明,这篇文章写的很清楚

[Android JNI 使用的数据结构JNINativeMethod详解]http://blog.csdn.net/bigapple88/article/details/6756204

参考文章:

Android JNI(实现自己的JNI_OnLoad函数)

Android的NDK开发(1)————Android JNI简介与调用流程

可能会遇到的陷阱(其中的内存释放问题我就遇到了):

Android NDK之JNI陷阱

27 Jan 2015