上一篇对NDK开发进行了说明,如果没看的建议先看一下,这里就不说了
http://blog.csdn.net/u014289337/article/month/2017/04
转换中需要注意的事项:
一:c语言开发要注意是面向过程的开发,Java是面向对象的开发,在我们习惯了Java的时候在c中进行编程,要注意需要先定义后调用
二:在字符串输出要输出定义并且转换的字符串
直接上代码
public class JniTest {
static {
System.loadLibrary("jary");
}
static public native String AddStr(String strA, String strB);
static public native int AddInt(int a, int b);
}
生成的.h文件(如何生成在上一篇文章中有详细步骤)
#include <jni.h>
/* Header for class encrypt_duojiankj_cn_jnitest_JniTest */
#ifndef _Included_encrypt_duojiankj_cn_jnitest_JniTest
#define _Included_encrypt_duojiankj_cn_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: encrypt_duojiankj_cn_jnitest_JniTest
* Method: AddStr
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddStr
(JNIEnv *, jclass, jstring, jstring);
/*
* Class: encrypt_duojiankj_cn_jnitest_JniTest
* Method: AddInt
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddInt
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
我们需要编写的.c文件
#include <jni.h>
#include <string.h>
#include "encrypt_duojiankj_cn_jnitest_JniTest.h"
/**
* 从JAVA传字符串到C++
* 上层JAVA数据类型String对应NDK为jstring类型,上层传参的方式和普通的java函数间调用并没有什么区别,重点是底层函数,
* 如何将上层传来的jstring转化成本地可认并且可以操作的char *数组
*
* 返回值 char* 这个代表char数组的首地址
* Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
*/
char* Jstring2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //String
jstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312"
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba, 0); //
return rtn;
}
JNIEXPORT jstring JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddStr
(JNIEnv *env, jclass org, jstring str1, jstring str2){
char* cstr1 = Jstring2CStr(env, str1);
char* cstr2 = Jstring2CStr(env, str2);
// char arr[7] = { ' ', 'h', 'e', 'l', 'l', 'o', '\0' };
strcat(cstr1, cstr2); //将cstr2合并到字符串cstr1
//从C++传字符串到java
return (*env)->NewStringUTF(env, cstr1);//输出的是定义的类型
}
JNIEXPORT jint JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddInt
(JNIEnv *env, jclass org, jint a, jint b){
return a + b;
}
总结:
上述这个简单的示例可以说明ndk开发中,Java是怎样将数据传递给C代码的了,程序中只是简单的介绍了一种数据类型string这是远远不够的,因为Java支持的数据类型比较多,这时候怎么办?好,有了上面的例子,我们可以举一反三了,在之前的博客中我也强调过ndk解压包下的jni.h这个文件的重要性,这个文件不仅仅定义了Java数据类型在C语言中的表示,看一下源码,就发现一种一一映射的关系:
......
typedef uint8_t jboolean; /* unsigned 8 bits */
typedef int8_t jbyte; /* signed 8 bits */
typedef uint16_t jchar; /* unsigned 16 bits */
typedef int16_t jshort; /* signed 16 bits */
typedef int32_t jint; /* signed 32 bits */
typedef int64_t jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
#else
typedef unsigned char jboolean; /* unsigned 8 bits */
typedef signed char jbyte; /* signed 8 bits */
typedef unsigned short jchar; /* unsigned 16 bits */
typedef short jshort; /* signed 16 bits */
typedef int jint; /* signed 32 bits */
typedef long long jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
......
另外还有一个非常重要的结构体JNINativeInterface,这里面定义了很多C函数,只要看懂大致意思就可以试着去调用这些函数,这些函数在native开发中显得特别重要:
jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);
jbyteArray (*NewByteArray)(JNIEnv*, jsize);
jcharArray (*NewCharArray)(JNIEnv*, jsize);
jshortArray (*NewShortArray)(JNIEnv*, jsize);
jintArray (*NewIntArray)(JNIEnv*, jsize);
jlongArray (*NewLongArray)(JNIEnv*, jsize);
jfloatArray (*NewFloatArray)(JNIEnv*, jsize);
jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);
jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);
jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);
jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);
jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);
jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);
jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);
jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);
源码比较长,有兴趣的朋友自己翻看一下,这里只贴部分