Created
April 16, 2019 08:48
-
-
Save Furzoom/3392fe00037c0861f9e1eb0f4e1fe304 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
最近做Android开发的人越来越多,Android开发难免会遇到调用本地库,这就需要采用JNI技术,JNI本身并不复杂,但大多数开发者在类型转换上遇到麻烦,今天特地将几种常用类型转换写成一个实例来告诉大家如何转换,尤其是Java的类和C的结构的转换,结构体中嵌套结构体如何处理,这部分网上的资料也比较少。 | |
1. 编写Java类 | |
package com.jinhill.util; | |
public class NativeModule { | |
public native int testArg(int i, boolean b, char c, double d); | |
public native byte[] testByte(byte[] b); | |
public native String[] testString(String s, String[] sarr); | |
public native int setInfo(MyInfo info); | |
public native MyInfo getInfo(); | |
static { | |
System.loadLibrary(“NativeModule”); | |
} | |
} | |
其中MyInfo类定义如下: | |
public class Record { | |
int id; | |
String name; | |
byte[] data; | |
} | |
public class MyInfo { | |
public boolean b; | |
public char c; | |
public double d; | |
public int i; | |
public byte[] array; | |
public String s; | |
public Record rec; | |
} | |
C自定义结构体 | |
typedef struct{ | |
int id; | |
char name[255]; | |
char data[255]; | |
}Record; | |
typedef struct{ | |
BOOL b; | |
char c; | |
double d; | |
int i; | |
char arr[255]; | |
char sz[255]; | |
Record rec; | |
}MyInfo; | |
2. 生成jni头文件 | |
1) 编译javac com/jinhill/util/NativeModule.java | |
2) javah –jni com.jinhill.util.NativeModule | |
这样com_jinhill_util_NativeModule.h文件就生成好了。 | |
3. 编写C库 | |
1) Java与C不同类型参数转换实例 | |
//不同类型参数处理 | |
JNIEXPORT jintJNICALL Java_com_jinhill_util_NativeModule_testArg | |
(JNIEnv *env, jobject jo, jint ji, jbooleanjb, jchar jc, jdouble jd) | |
{ | |
//获取jint型值 | |
int i = ji; | |
//获取jboolean型值 | |
BOOL b = jb; | |
//获取jdouble型值 | |
double d = jd; | |
//获取jchar型值,Java的char两字节 | |
char ch[5] = {0}; | |
int size = 0; | |
size = WideCharToMultiByte(CP_ACP,NULL, (LPCWSTR)&jc, -1, ch, 5, NULL, FALSE); | |
if(size <= 0) | |
{ | |
return -1; | |
} | |
Trace(“ji=%d,jb=%d,jc=%s,jd=%lf”,i, b, ch, d); | |
return 0; | |
} | |
2) Java byte与C char数组类型数组转换实例 | |
//btye数组处理,形参作为输入或输出,返回btye数组 | |
JNIEXPORTjbyteArray JNICALL Java_com_jinhill_util_NativeModule_testByte | |
(JNIEnv *env, jobject jo, jbyteArray jbArr) | |
{ | |
char chTmp[] = “Hello JNI!”; | |
int nTmpLen = strlen(chTmp); | |
//获取jbyteArray | |
char *chArr = (char*)env->GetByteArrayElements(jbArr,0); | |
//获取jbyteArray长度 | |
int nArrLen = env->GetArrayLength(jbArr); | |
char *szStrBuf =(char*)malloc(nArrLen*2+10); | |
memset(szStrBuf, 0, nArrLen*2+10); | |
Bytes2String(chArr, nArrLen, szStrBuf,nArrLen*2+10); | |
Trace(“jbArr=%s”, szStrBuf); | |
//将jbArr作为输出形参 | |
memset(chArr, 0, nArrLen); | |
memcpy(chArr, chTmp, nTmpLen); | |
//返回jbyteArray | |
jbyteArray jarrRV =env->NewByteArray(nTmpLen); | |
jbyte *jby =env->GetByteArrayElements(jarrRV, 0); | |
memcpy(jby, chTmp, strlen(chTmp)); | |
env->SetByteArrayRegion(jarrRV, 0,nTmpLen, jby); | |
return jarrRV; | |
} | |
3) Java String与C char数组类型转换实例 | |
//String 和String[]处理 | |
JNIEXPORTjobjectArray JNICALL Java_com_jinhill_util_NativeModule_testString | |
(JNIEnv *env, jobject jo, jstring jstr,jobjectArray joarr) | |
{ | |
int i = 0; | |
char chTmp[50] = {0}; | |
//获取jstring值 | |
const char* pszStr = (char*)env->GetStringUTFChars(jstr, 0); | |
Trace(“jstr=%s”, pszStr); | |
//获取jobjectArray值 | |
int nArrLen =env->GetArrayLength(joarr); | |
Trace(“joarr len=%d”,nArrLen); | |
for(i=0; i<nArrLen; i++) | |
{ | |
jstring js =(jstring)env->GetObjectArrayElement(joarr, i); | |
const char* psz = (char*)env->GetStringUTFChars(js, 0); | |
Trace(“joarr[%d]=%s”,i, psz); | |
} | |
//将joarr作为输出形参 | |
jstring jstrTmp = NULL; | |
for(i=0; i<nArrLen; i++) | |
{ | |
sprintf(chTmp, “No.%dHello JNI!”, i); | |
jstrTmp =env->NewStringUTF(chTmp); | |
env->SetObjectArrayElement(joarr,i, jstrTmp); | |
env->DeleteLocalRef(jstrTmp); | |
} | |
//返回jobjectArray | |
jclass jstrCls =env->FindClass(“Ljava/lang/String;”); | |
jobjectArray jstrArray =env->NewObjectArray(2, jstrCls, NULL); | |
for(i=0; i<2; i++) | |
{ | |
sprintf(chTmp, “No. %dReturn JNI!”, i); | |
jstrTmp =env->NewStringUTF(chTmp); | |
env->SetObjectArrayElement(jstrArray,i, jstrTmp); | |
env->DeleteLocalRef(jstrTmp); | |
} | |
return jstrArray; | |
} | |
4) Java 类与C结构体类型转换实例 | |
JNIEXPORT jint JNICALL Java_com_jinhill_util_NativeModule_setInfo | |
(JNIEnv *env, jobject jo, jobject jobj) | |
{ | |
char chHexTmp[512] = {0}; | |
//将Java类转换成C结构体 | |
MyInfo mi; | |
//获取Java中的实例类Record | |
jclass jcRec = env->FindClass(“com/jinhill/util/Record”); | |
//int id | |
jfieldID jfid = env->GetFieldID(jcRec, “id”, “I”); | |
//String name | |
jfieldID jfname = env->GetFieldID(jcRec, “name”, “Ljava/lang/String;”); | |
//byte[] data; | |
jfieldID jfdata = env->GetFieldID(jcRec, “data”, “[B”); | |
//获取Java中的实例类MyInfo | |
jclass jcInfo = env->FindClass(“com/jinhill/util/MyInfo”); | |
//获取类中每一个变量的定义 | |
//boolean b | |
jfieldID jfb = env->GetFieldID(jcInfo, “b”, “Z”); | |
//char c | |
jfieldID jfc = env->GetFieldID(jcInfo, “c”, “C”); | |
//double d | |
jfieldID jfd = env->GetFieldID(jcInfo, “d”, “D”); | |
//int i | |
jfieldID jfi = env->GetFieldID(jcInfo, “i”, “I”); | |
//byte[] array | |
jfieldID jfa = env->GetFieldID(jcInfo, “array”, “[B”); | |
//String s | |
jfieldID jfs = env->GetFieldID(jcInfo, “s”, “Ljava/lang/String;”); | |
//Record rec; | |
jfieldID jfrec = env->GetFieldID(jcInfo, “rec”, “Lcom/jinhill/util/Record;”); | |
//获取实例的变量b的值 | |
mi.b = env->GetBooleanField(jobj, jfb); | |
//获取实例的变量c的值 | |
jchar jc = env->GetCharField(jobj, jfc); | |
char ch[5] = {0}; | |
int size = 0; | |
size = WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)&jc, -1, ch, 5, NULL, FALSE); | |
mi.c = ch[0]; | |
//获取实例的变量d的值 | |
mi.d = env->GetDoubleField(jobj, jfd); | |
//获取实例的变量i的值 | |
mi.i = env->GetIntField(jobj, jfi); | |
//获取实例的变量array的值 | |
jbyteArray ja = (jbyteArray)env->GetObjectField(jobj, jfa); | |
int nArrLen = env->GetArrayLength(ja); | |
char *chArr = (char*)env->GetByteArrayElements(ja, 0); | |
memcpy(mi.arr, chArr, nArrLen); | |
//获取实例的变量s的值 | |
jstring jstr = (jstring)env->GetObjectField(jobj, jfs); | |
const char* pszStr = (char*)env->GetStringUTFChars(jstr, 0); | |
strcpy(mi.sz, pszStr); | |
//获取Record对象 | |
jobject joRec = env->GetObjectField(jobj, jfrec); | |
//获取Record对象id值 | |
mi.rec.id = env->GetIntField(joRec, jfid); | |
Trace(“mi.rec.id=%d”,mi.rec.id); | |
//获取Record对象name值 | |
jstring jstrn = (jstring)env->GetObjectField(joRec, jfname); | |
pszStr = (char*)env->GetStringUTFChars(jstrn, 0); | |
strcpy(mi.rec.name, pszStr); | |
//获取Record对象data值 | |
jbyteArray jbd = (jbyteArray)env->GetObjectField(joRec, jfdata); | |
nArrLen = env->GetArrayLength(jbd); | |
chArr = (char*)env->GetByteArrayElements(jbd, 0); | |
memcpy(mi.rec.data, chArr, nArrLen); | |
//日志输出 | |
Bytes2String(mi.arr, nArrLen, chHexTmp, sizeof(chHexTmp)); | |
Trace(“mi.arr=%s, mi.b=%d, mi.c=%c, mi.d=%lf, mi.i=%d, \n mi.sz=%s\n mi.rec.id=%d, mi.rec.name=%s”, chHexTmp, mi.b, mi.c, mi.d, mi.i, mi.sz, mi.rec.id, mi.rec.name); | |
return 0; | |
} | |
5) C结构体类型与Java 类转换实例 | |
JNIEXPORT jobject JNICALL Java_com_jinhill_util_NativeModule_getInfo | |
(JNIEnv *env, jobject jo) | |
{ | |
wchar_t wStr[255] = {0}; | |
char chTmp[] = “Hello JNI”; | |
int nTmpLen = strlen(chTmp); | |
//将C结构体转换成Java类 | |
MyInfo mi; | |
memcpy(mi.arr, chTmp, strlen(chTmp)); | |
mi.b = TRUE; | |
mi.c = ‘B’; | |
mi.d = 2000.9; | |
mi.i = 8; | |
strcpy(mi.sz, “Hello World!”); | |
mi.rec.id = 2011; | |
memcpy(mi.rec.data, “\x01\x02\x03\x04\x05\x06”, 6); | |
strcpy(mi.rec.name, “My JNI”); | |
//获取Java中的实例类Record | |
jclass jcRec = env->FindClass(“com/jinhill/util/Record”); | |
//int id | |
jfieldID jfid = env->GetFieldID(jcRec, “id”, “I”); | |
//String name | |
jfieldID jfname = env->GetFieldID(jcRec, “name”, “Ljava/lang/String;”); | |
//byte[] data; | |
jfieldID jfdata = env->GetFieldID(jcRec, “data”, “[B”); | |
//获取Java中的实例类 | |
jclass jcInfo = env->FindClass(“com/jinhill/util/MyInfo”); | |
//获取类中每一个变量的定义 | |
//boolean b | |
jfieldID jfb = env->GetFieldID(jcInfo, “b”, “Z”); | |
//char c | |
jfieldID jfc = env->GetFieldID(jcInfo, “c”, “C”); | |
//double d | |
jfieldID jfd = env->GetFieldID(jcInfo, “d”, “D”); | |
//int i | |
jfieldID jfi = env->GetFieldID(jcInfo, “i”, “I”); | |
//byte[] array | |
jfieldID jfa = env->GetFieldID(jcInfo, “array”, “[B”); | |
//String s | |
jfieldID jfs = env->GetFieldID(jcInfo, “s”, “Ljava/lang/String;”); | |
//Record rec; | |
jfieldID jfrec = env->GetFieldID(jcInfo, “rec”, “Lcom/jinhill/util/Record;”); | |
//创建新的对象 | |
jobject joRec = env->AllocObject(jcRec); | |
env->SetIntField(joRec, jfid, mi.rec.id); | |
jstring jstrn = env->NewStringUTF(mi.rec.name); | |
env->SetObjectField(joRec, jfname, jstrn); | |
jbyteArray jbarr = env->NewByteArray(6); | |
jbyte *jb = env->GetByteArrayElements(jbarr, 0); | |
memcpy(jb, mi.rec.data, 6); | |
env->SetByteArrayRegion(jbarr, 0, 6, jb); | |
env->SetObjectField(joRec, jfdata, jbarr); | |
//创建新的对象 | |
jobject joInfo = env->AllocObject(jcInfo); | |
//给类成员赋值 | |
env->SetBooleanField(joInfo, jfb, mi.b); | |
// MultiByteToWideChar (CP_ACP, 0, mi.c, -1, wStr, 255); | |
// env->SetCharField(joInfo, jfc, (jchar)wStr); | |
env->SetCharField(joInfo, jfc, (jchar)mi.c); | |
env->SetDoubleField(joInfo, jfd, mi.d); | |
env->SetIntField(joInfo, jfi, mi.i); | |
jbyteArray jarr = env->NewByteArray(nTmpLen); | |
jbyte *jby = env->GetByteArrayElements(jarr, 0); | |
memcpy(jby, mi.arr, nTmpLen); | |
env->SetByteArrayRegion(jarr, 0, nTmpLen, jby); | |
env->SetObjectField(joInfo, jfa, jarr); | |
jstring jstrTmp = env->NewStringUTF(chTmp); | |
env->SetObjectField(joInfo, jfs, jstrTmp); | |
env->SetObjectField(joInfo, jfrec, joRec); | |
return joInfo; | |
} | |
4. 编写Java测试代码 | |
public class TestInfo { | |
/** | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
int i =0; | |
String[] sArr = new String[2]; | |
for(i=0; i<2; i++) | |
{ | |
sArr[i] = “ID=” + i; | |
} | |
byte[] b = new byte[10]; | |
for(i=0; i<10; i++) | |
{ | |
b[i] = (byte)i; | |
} | |
MyInfo mi = new MyInfo(); | |
mi.array = b; | |
mi.b = false; | |
mi.c = ‘C’; | |
mi.d = 2011.11; | |
mi.i = 1752; | |
mi.s = “Hello World!”; | |
mi.rec = new Record(); | |
mi.rec.id = 2012; | |
mi.rec.name = “Record”; | |
mi.rec.data = b; | |
NativeModule nm = new NativeModule(); | |
nm.testArg(mi.i, mi.b, mi.c, mi.d); | |
byte[] b2 = nm.testByte(mi.array); | |
String[] s = nm.testString(mi.s, sArr); | |
nm.setInfo(mi); | |
MyInfo mi2 = nm.getInfo(); | |
System.out.println(“finish”); | |
} | |
} | |
5. Java String与 C char数组转换时的中文问题 | |
//将jstring类型转换成windows类型 | |
char* jstringToWindows( JNIEnv *env, jstring jstr ) | |
{ | |
int length = (env)->GetStringLength(jstr ); | |
const jchar* jcstr = (env)->GetStringChars(jstr, 0 ); | |
char* rtn = (char*)malloc( length*2+1 ); | |
int size = 0; | |
size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length,rtn,(length*2+1), NULL, NULL ); | |
if( size <= 0 ) | |
return NULL; | |
(env)->ReleaseStringChars(jstr, jcstr ); | |
rtn[size] = 0; | |
return rtn; | |
} | |
//将windows类型转换成jstring类型 | |
jstring WindowsTojstring( JNIEnv* env, char* str ) | |
{ | |
jstring rtn = 0; | |
int slen = strlen(str); | |
unsigned short * buffer = 0; | |
if( slen == 0 ) | |
rtn = (env)->NewStringUTF(str ); | |
else | |
{ | |
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 ); | |
buffer = (unsigned short *)malloc( length*2 + 1 ); | |
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length )>0 ) | |
rtn = (env)->NewString( (jchar*)buffer, length ); | |
} | |
if( buffer ) | |
free( buffer ); | |
return rtn; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment