之前用jni 技术一直是传输一些简单的数据结构,int float ,int[] float[] byte[] 这些简单的数据格式,但是如果数据比较多,一个返回值表示不完,需要调用多个函数返回,这样就导致程序接口复杂,如果程序加锁,还不能在一个函数里面完成,那该怎么处理呢,如果能像 c/c++ 一样返回一个结构体(也就是java中的类)那该多好啊,研究一段时间终于成功
struct info
{
int faceNum; // 数量
char * Base64CutImage; // Base64图片对应 java String
char * ByteCutImage; // 数组对应java byte[] ,长度不确定
}
https://blog.csdn.net/baidu_31872269/article/details/85055573
最好是参考上一篇是如何创建工程的
测试环境是win10 , eclipse java 工程,vs2015 生成dll
如果想在Android上用,此博客也适用
好吧,还是啰嗦一下吧
eclipse 创建一个工程JavaGetCstruct
在src下面创建一个包com.faceos.jni
在包下面创建三个类
InterfaceJNI.java // 接口类
ResultInfo.java // 返回的结构体类
test.java // 测试类
InterfaceJNI.java
package com.faceos.jni;
public class InterfaceJNI {
public static native ResultInfo getResult(); // 静态接口类,返回值是一个类
static{
System.out.println("teststruct !");
System.loadLibrary("teststruct");
}
}
ResultInfo.java
package com.faceos.jni;
public class ResultInfo {
private int faceNum;
private String Base64CutImage;
private byte[] byteCutImage;
public int getfaceNum()
{
return faceNum;
}
public String getBase64CutImage()
{
return Base64CutImage;
}
public byte[] getByteCutImage()
{
return byteCutImage;
}
public ResultInfo(int faceNum_, String Base64CutImage_, byte[] byteCutImage_)
{
this.faceNum = faceNum_;
this.Base64CutImage = Base64CutImage_;
this.byteCutImage = byteCutImage_;
}
}
test.java
package com.faceos.jni;
public class test {
public static void main(String[] args) {
ResultInfo resultInfo = InterfaceJNI.getResult();
System.out.println("faceNum = " + resultInfo.getfaceNum());
System.out.println("String = " + resultInfo.getBase64CutImage());
System.out.println("byteCutImage = " + resultInfo.getByteCutImage().length);
for(int i = 0; i < resultInfo.getByteCutImage().length; i ++)
{
System.out.println("a["+i + "] = " + resultInfo.getByteCutImage()[i]);
}
}
}
ok java工程创建完毕
vs 创建一个工程控制台程序teststruct,空项目
创建一个main.cpp
#include <stdio.h>
int main()
{
return 0;
}
javah 命令把InterfaceJNI.class 生产头文件
拷贝到工程目录下
创建一个InterfaceJNI.cpp
#include "com_faceos_jni_InterfaceJNI.h"
extern "C"
{
JNIEXPORT jobject JNICALL Java_com_faceos_jni_InterfaceJNI_getResult
(JNIEnv *env, jobject obj)
{
jclass jclassResultInfo = env->FindClass("com/faceos/jni/ResultInfo"); // 获取类 引用
jmethodID jidResultInfo =
env->GetMethodID(jclassResultInfo, "<init>", "(ILjava/lang/String;[B)V"); // 获取类的方法,此方法是构造函数
// "(ILjava/lang/String;[B)V" 解释一下这个字符串,V代表返回空类型, ()号里面代表三个参数, 分解成三个分别是(我用空格隔开) I Ljava/lang/String; [B 分别代表整数,字符string,和byte[] 自己体会
int faceNum = 1;
jstring jstr = env->NewStringUTF("hello world ");
int mSize = 100;
char buffer[100] = { 0 };
for (int i = 0; i < mSize; i++)
{
buffer[i] = i;
}
jbyteArray byteA = env->NewByteArray(mSize);
env->SetByteArrayRegion(byteA, 0, mSize, (const jbyte*)buffer);
jobject result = env->NewObject(jclassResultInfo, jidResultInfo, faceNum, jstr, byteA); // 返回值不需要要释放
env->DeleteLocalRef(byteA); // 中间变量需要释放
env->DeleteLocalRef(jstr); // 中间变量需要释放
return result;
}
}
好了,配置一个jni 路径,在jdk 下面
在属性下面设置生产动态库dll
编译就可生产dll
将dll 拷贝到eclispe 指定lib 路径下,或者把dll 所在路径配置到环境变量下面,执行eclipse 就可以啦
工程代码
https://download.csdn.net/download/baidu_31872269/10865531
代码更正,需要释放jmethodID, 所以把这个初始化时候存起来
#include "com_faceos_jni_InterfaceJNI.h"
JavaVM* vm_global;
jclass jclassResultInfo;
extern "C"
{
// 这个函数不用手动调用,加载库时候自动调用,如果不重载就不调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
vm_global = vm;
jclass jclassResultInfo_temp = env->FindClass("com/faceos/jni/ResultInfo"); // 获取类 引用
jclassResultInfo = (jclass)env->NewGlobalRef(jclassResultInfo_temp);
LOGE("JNI_OnLoad ok .....");
return JNI_VERSION_1_6;
}
// 和上个函数相反
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return;
}
env->DeleteGlobalRef(jclassResultInfo);
}
JNIEXPORT jobject JNICALL
Java_com_faceos_jni_InterfaceJNI_getResult
(JNIEnv *env, jobject obj)
{
// jclass jclassResultInfo = env->FindClass("com/faceos/jni/ResultInfo"); // 获取类 引用
jmethodID jidResultInfo =
env->GetMethodID(jclassResultInfo, "<init>", "(ILjava/lang/String;[B)V"); // 获取类的方法,此方法是构造函数
// "(ILjava/lang/String;[B)V" 解释一下这个字符串,V代表返回空类型, ()号里面代表三个参数, 分解成三个分别是(我用空格隔开) I Ljava/lang/String; [B 分别代表整数,字符string,和byte[] 自己体会
int faceNum = 1;
jstring jstr = env->NewStringUTF("hello world ");
int mSize = 100;
char buffer[100] = { 0 };
for (int i = 0; i < mSize; i++)
{
buffer[i] = i;
}
jbyteArray byteA = env->NewByteArray(mSize);
env->SetByteArrayRegion(byteA, 0, mSize, (const jbyte*)buffer);
jobject result = env->NewObject(jclassResultInfo, jidResultInfo, faceNum, jstr, byteA); // 返回值不需要要释放
env->DeleteLocalRef(byteA); // 中间变量需要释放
env->DeleteLocalRef(jstr); // 中间变量需要释放
return result;
}
}