一.生成.h文件
- win+x,运行 cmd,cd java工程class文件所在bin文件夹
- 运行 javah -classpath .\ -jni <classes>
- bin文件夹的同级目录生成<classes>.h文件
- vs2010打开<classes>.h文件,<jni.h> 修改为 "jni.h"
- vs2010 新建 <classes>.cpp文件,编写JNI本地 函数
二.JNI本地函数编写细则
- java String 参数传递
- char* jstringToWindows( JNIEnv *env, jstring jstr )
{ //UTF8/16转换成gb2312
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;
} - jstring WindowsTojstring( JNIEnv* env, const char* str )
{//gb2312转换成utf8/16
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;
}
- c++ 结构体与java 类的对应关系
- java没有结构体的概念,若JNI函数需反馈结构体变量,则java调用层需定义相应的class
- 结构体内嵌结构体,对应class内嵌class.
结构体定义:
typedef struct _VoiceAPIStat
{
int nSLESRecOpenSucceedCnt;
int nSLESRecOpenFailedCnt;
int nSLESPlayOpenSucceedCnt;
}VoiceAPIStat;
//-------------------------------------------------------------------------------------------------------
typedef struct _EngRunInfoStat
{
bool bStatisticsEnable;
int nStatisticsLevel;
int nRptIntervalInMs;
VoiceAPIStat stVoiceApiStat;
}EngRunInfoStat;
Java类相应定义:
public class EngRunInfoStat
{
public boolean bStatisticsEnable;
public int nStatisticsLevel;
public int nRptIntervalInMs;
public VoiceAPIStat stVoiceApiStat;
public class VoiceAPIStat
{
public int nSLESRecOpenSucceedCnt;
public int nSLESRecOpenFailedCnt;
public int nSLESPlayOpenSucceedCnt;
};
};
3.结构体内嵌结构体数组,对应类内嵌类数组
- 基本数据类型常用操作函数(JNI调用事例)
(env)->SetBooleanField(objectEng,nGroup,GroupNo);
(env)->SetDoubleField(objectEng,dwQu,Qu);
jstr = WindowsTojstring(env,“test”);
(env)->SetObjectField(objectEng,chNote,jstr);
(env)->SetCharField(objectEng,wNum,Number);
GetBooleanField 获取不同数据类型字段值 相关函数
- 对象数组操作示例(结构体参数值反馈java类)
jobjectArray InfoAry = 0;
jsize jNum = pItem->GetNumber();
InfoAry = (env)->NewObjectArray(jNum, objClass, 0);
jclass jInfo = (env)->FindClass("test/common/docu/taglnfo");
//获取成员变量
jmethodID InitInfoID = (env)->GetMethodID(jInfo, "<init>", "()V");
jobject objInfo;
jfieldID strName = (env)->GetFieldID(jInfo, "strName", "Ljava/lang/String;");
jfieldID nWave = (env)->GetFieldID(jInfo, "nWave ", "I");
for (int j = 0; j < jNum; j++)
{
objInfo = (env)->NewObject(jInfo ,InitInfoID);
jstr = WindowsTojstring(env, Name);
(env)->SetObjectField(objInfo ,strName,jstr);
(env)->SetIntField(objInfo ,nWave ,nLen);
(env)->SetObjectArrayElement(InfoAry, j, objInfo );
}
赋值上一级(InfoAry 为一个Object成员)
(env)->SetObjectField(objectEng,TestInfoArray,InfoAry);
三.基本相关的cmd命令
- 查看签名
- cd java工程bin文件夹;
- 运行 javap -s 类全名(e.g. "test.common.document.tagHead")
- 类全名获取方式: 将该类点开,然后选中类名,右键选择copy qualified name.(eclipse)
- 内嵌类的签名比较特殊,首先是L开头代表类,然后包名,外部类与内部类签名之间用$隔开,即“Lcom/test/eng/EngRunInfoStat$VoiceAPIStat;”
相关网站链接:http://www.ceeger.com/Script/AndroidJNI/AndroidJNI.html