Android(Java):Android ndk开发

书写Java native接口

知识点:

javah -classpath . -jni com.test.jni.FileJNILib

将Java的String转为C的字符串,字符串的转换如下:

const charconst *p_passwd = (*env)->GetStringUTFChars(env, j_passwd, NULL);

c 代码中声明字符串数组,调用NewStringUTF,即可转为Java String
char szName[256];
(*env)->NewStringUTF(env,szName);

下面我们进入实战的阶段,写代码。

建立一个android1.5的项目,NDK不支持1.5以下的版本


Android(Java):Android ndk开发_第1张图片

JNI.java的代码:


Android(Java):Android ndk开发_第2张图片


 JniTest.java的代码:


Android(Java):Android ndk开发_第3张图片

4. 生成JNI 头文件

下面生成JNI头文件啦,使用javah命令,对JNI..java这个文件生成,别搞错啦!

使用cmd进入Android项目的bin目录中,然后执行 javah -classpath .  -jni cc.androidos.jni.JNI这个命令。别忘记包名!(^_^)


Android(Java):Android ndk开发_第4张图片

生成了一个cc_androidos_jni_JNI.h

打开看看:


Android(Java):Android ndk开发_第5张图片

里面都是c语言的头文件声明

5. 书写C代码,写入数据

下面进行c语言代码的阶段,不会C的,可以去学习一下。

我这里使用eclipse for c/c++的进行开发,简单的代码大家可以使用记事本。

工程如下:


Android(Java):Android ndk开发_第6张图片

cc_androidos_jni_JNI.h内容不变

cc_androidos_jni_JNI.c的内容:


Android(Java):Android ndk开发_第7张图片

在这里的代码会在运行的时候向sdcard写入androidos.cc.txt文件。然后写入aaaa数据。

6. 编译SO文件

进行编译so文件:

在NDK的apps目录下面创建一个myjni文件夹,在myjni文件夹中创建一个Application.mk文件,文件的内容为:


Android(Java):Android ndk开发_第8张图片

在NDKsources目录下创建myjni文件夹,在myjni文件中创建一个Android.mk文件,然后将cc_androidos_jni_JNI.h和cc_androidos_jni_JNI.c文件copy进来:


Android(Java):Android ndk开发_第9张图片

Android.mk中的内容如下: LOCAL_SRC_FILES := com_test_jni_FileJNILib.c common.c


Android(Java):Android ndk开发_第10张图片

里面内容的关键字含义请自行查看docs\OVERVIEW.TXT文件

编译:


Android(Java):Android ndk开发_第11张图片

7. 加入到Android项目中进行运行

将apps\myjni\libs整个文件夹copy到android项目下:


Android(Java):Android ndk开发_第12张图片

运行android项目使用adb shell进行查看:


Android(Java):Android ndk开发_第13张图片

进入sdcard查看数据。

注意:sdcard具有system的权限,如果你的目录是root权限的,那么是不能写成功的,除非是真机越权,模拟器是不成功的,并且在Eclipse logcat下会有DEBUG信息出现。


NOT FOUND JNI_OnLoad问题:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include

#include

#include //jni的主要头文件


#include "com_test_jni_FileJNILib.h"
/* Header for class com_test_jni_FileJNILib */

/*
 * Class:     com_test_jni_FileJNILib
 * Method:    fileCrypt
 * Signature: (Ljava/lang/String;Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_test_jni_FileJNILib_fileCrypt__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv * env, jclass thiz, jstring source, jstring dest){
 return 1;
}

/*
 * Class:     com_test_jni_FileJNILib
 * Method:    fileCrypt
 * Signature: (Ljava/io/File;)Ljava/io/File;
 */
JNIEXPORT jobject JNICALL Java_com_test_jni_FileJNILib_fileCrypt__Ljava_io_File_2
  (JNIEnv * env, jclass thiz, jobject source){
 return NULL;
}

static const JNINativeMethod gMethods[] = { //定义批量注册的数组,是注册的关键部分

{"fileCrypt", "(Ljava/lang/String;Ljava/lang/String;)I", (void*)Java_com_test_jni_FileJNILib_fileCrypt__Ljava_lang_String_2Ljava_lang_String_2} ,// func2是在java中声明的native函数名,"()V"是函数的签名,可以通过javah获取。
{"fileCrypt", "(Ljava/io/File;)Ljava/io/File;", (void*)Java_com_test_jni_FileJNILib_fileCrypt__Ljava_io_File_2}
};


JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved) //这是JNI_OnLoad的声明,必须按照这样的方式声明

{

JNIEnv* env = NULL; //注册时在JNIEnv中实现的,所以必须首先获取它

jint result = -1;


if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本

  return -1;

jclass clazz;

static const char* const kClassName="com/test/jni/FileJNILib";

clazz = (*env)->FindClass(env, kClassName); //这里可以找到要注册的类,前提是这个类已经加载到java虚拟机中。 这里说明,动态库和有native方法的类之间,没有任何对应关系。

if(clazz == NULL)

{

  printf("cannot get class:%s\n", kClassName);

  return -1;

}

if((*env)->RegisterNatives(env, clazz,gMethods, sizeof(gMethods)/sizeof(gMethods[0]))!= JNI_OK) //这里就是关键了,把本地函数和一个java类方法关联起来。不管之前是否关联过,一律把之前的替换掉!

{

  printf("register native method failed!\n");

  return -1;

}

return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。

}

你可能感兴趣的:(Android(Java):Android ndk开发)