一、JNI简介
在项目开发中,如果需要调用第三方库或者操作系统相关功能,那么在java环境中需要使用到JNI技术。
从java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许java代码和其他语言进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
当然相比于JNI个人觉得JNA更为简单;什么是JNA可自行百度。
二、JNI的使用示例
话不多说,直接上例子,主要介绍生成.h文件,后续编库使用,参考其他。
1、例子
student类
public class Student {
}
GlApi类
public class GlApi {
public native int add(int x, int y);
public native Student del(int name);
}
2、生成.h文件
一、使用javac生成.class文件
javac jnik\GlApi.java
二、使用javah生成.h文件
javah -jni jnik.GlApi
此时生成.h文件
三、错误处理
1、在生成.h文件时,如果出现Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name: jnik\GlApi,那么是因为使用命令不对,此时使用了javah jnik\GlApi造成上述问题。
解决办法:使用命令如下(注意观察文件.java所在的文件目录,可参考用javah导出类的头文件,Not a valid class name或者错误: 找不到 'HelloNDK' 的类文件_exception in thread "main" java.lang.illegalargume-CSDN博客
javac -jni jnik.GlApi
2、在项目开发中,不得随意移动GlApi的位置,否则会造成java.lang.unsatisfiedLinkerror:GlApi.xxxxxxx(Ljava/lang/Object;)Lentity/RecvEntity;,究其原因,是因为生成.h文件时,在编译库时,位置已经指定。注意观察.h的文件名和其内容
请自行体会,这点本人花费较多时间才发现。
三、补充JNI接口参数为对象时赋值
class recvEntity
{
String id,
int taskid,
int result,
String data;
}
JNIEXPORT jobject JNICALL Java_jni_GlApi_recvfile(JNIEnv *,jobject, jobject);
JNIEXPORT jobject JNICALL Java_jni_GlApi_recvfile(JNIEnv *,jobject, jobject recvEntity)
{
//获取对象
jclass JREcvEntity = env->GetObjectClass(recvEntity);
//获取方法名和名称ID
jmethodID method_init_id = env->GetMethodID(jREcvEntity, "<init>", "()V");
//从class中获取变量
jfieldID fperrid = env->GetFieldID(jREcvEntity, "peerid", "[B");
jfieldID ftaskId = env->GetFieldID(JREcvEntity, "taskid", "I");
jfieldID fresult = env->GetFieldID(JREcvEntity, "result", "I");
jfieldID fdata = env->GetFieldID(jREcvEntity, "data", "[B");
//创建临时对象
jobject tm_recvEntity = env->NewObject(JREcvEntity, method_init_id);
unsigned int f_data_len = 0;
unsigned int f_peerid = 0;
unsigned int f_taskid = 0;
unsigned char *file_data = NULL;
unsigned char ipId[16] = {0};
int ret = 0;
//调用业务接口
ret = marketing_trans(ipId, &f_taskid, &file_data, &file_data_len);
if(ret != 0)
{
return NULL;
}
//先分配空间
jbyteArray ipdata = env->NewByteArray(16);
//赋值
env->SetByteArrayRegion(ipdata, 0, 16, (const jbyte*)ipId);
//转化
char *ipArr = (char *)env->GetByteArrayElements(ipdata, 0);
env->SetObjectField(tm_recvEntity, fpeerid, env->NewStringUTF(ipArr));
//释放
env->DeleteLocalRef(ipdata);
env->SetIntField(tm_recvEntity, ftaskId, f_taskid);
env->SetIntField(tm_recvEntity, fresult, f_data_len);
jbyteArray data = env->NewByteArray(f_data_len);
env->SetByteArrayRegion(data, 0, f_data_len, (const jbyte*)file_data);
char *chArr = (char*)env->GetByteArrayElements(data, 0);
env->SetObjectField(tm_recvEntity, fdata, env->NewStringUTF(chArr));
//删除局部引用
env->DeleteLocalRef(data);
free(file_data);
file_data = NULL;
return tm_recvEntity;
}