ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java 封装jni 数据返回 结构体传递 等

2022-01-25 10:31:52  阅读:226  来源: 互联网

标签:封装 int SendSMS env printf debug java jni


近期需要c和java进行数据交互,使用jni技术,网上教程也参考不少,我这里参考一些案例 做一些汇总,帮后来人少一些弯路

win

1 直接使用vs创建dll工程,运行相关代码会出现找不到jni.h的问题, 这个也好做 在项目属性界面 vc 目录中 包含目录 添加java的include就可以了( win这个样子没问题)

 

 

 另一个问题是预编译头问题,(此处不使用预编译头,因为要做到代码在linux也照样跑起来)

 

 

2 编译时候切换debug和release,可能需要重新填写以上信息 另一点,debug生成的 dll 库,可能导致在无vc环境的电脑无法使用 因此win对外发布时,需要使用release生成的dll库

3 关于动态库编译时,头文件生成 建议使用java自己生成.如下

对于java10 之前的 使用 javac SendSMS.java生成.class文件再 javach SendSMS生成.h文件

对于java10 之后的 使用 javac -h . SendSMS.java

class SendSMS {
	public native int SmsInit();
	public native int SmsSend(byte[] mobileNo, byte[] smContent);
	public native int foo(Foo fooObj);
	public native int SmsRead(int  x,int y,double[]  cText);
}

自动生成的.h文件如下  SendSMS.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class SendSMS */

#ifndef _Included_SendSMS
#define _Included_SendSMS
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     SendSMS
 * Method:    SmsInit
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_SendSMS_SmsInit
  (JNIEnv *, jobject);

/*
 * Class:     SendSMS
 * Method:    SmsSend
 * Signature: ([B[B)I
 */
JNIEXPORT jint JNICALL Java_SendSMS_SmsSend
  (JNIEnv *, jobject, jbyteArray, jbyteArray);

/*
 * Class:     SendSMS
 * Method:    foo
 * Signature: (LFoo;)I
 */
JNIEXPORT jint JNICALL Java_SendSMS_foo
  (JNIEnv *, jobject, jobject);

/*
 * Class:     SendSMS
 * Method:    SmsRead
 * Signature: (II[D)I
 */
JNIEXPORT jint JNICALL Java_SendSMS_SmsRead
  (JNIEnv *, jobject, jint, jint, jdoubleArray);

#ifdef __cplusplus
}
#endif
#endif

后面就根据生成的这个.h开发响应的函数 如下  SendSMS.c

#include <jni.h>
typedef struct chuanStruts {
    int y;
    double doubletext[40];
} smsstruts;

typedef struct Foo {
    int len;
    char name[100];
} Foo_t;

JNIEXPORT jint JNICALL Java_SendSMS_SmsInit(JNIEnv *ev, jobject obj) {
    return SmsInit();
    //调用sms.c里的SmsInit方法
}
JNIEXPORT jint JNICALL Java_SendSMS_SmsSend(JNIEnv *ev, jobject obj, jbyteArray mobileno, jbyteArray smscontent) {
    char * psmscontent ;
    //jsize thearraylengthj = (*env)->getarraylength(env,mobileno);
    jbyte * arraybody = (*ev)->GetByteArrayElements(ev,mobileno,0);
    char * pmobileno = (char *)arraybody;
    printf("[%s]/n ", pmobileno);
    //jsize size = (*env)->getarraylength(env,smscontent);
    arraybody = (*ev)->GetByteArrayElements(ev,smscontent,0);
    psmscontent = (char *)arraybody;
    return SmsSend(pmobileno,psmscontent);
    //调用sms.c里的SmsSend方法
}
JNIEXPORT jint JNICALL Java_SendSMS_SmsRead (JNIEnv *ev, jobject obj, jint x,jint y, jdoubleArray doubletext) {
    smsstruts example;
    //自己构建的example结构体变量
    double * psmscontent ;
    int i;
    jdouble * arraybody = (*ev)->GetDoubleArrayElements(ev,doubletext,0);
    psmscontent = (double *)arraybody;
    printf("%f",*psmscontent);
    printf("%f",*(psmscontent+1));
    example.y= y;
    for (i=0;i<2;i++) {
        example.doubletext[i] = *(psmscontent+i);
    }
    return SmsRead(x,&example);
    //调用sms.c里的SmsRead方法
}

JNIEXPORT jint JNICALL Java_SendSMS_foo(JNIEnv* env, jobject obj, jobject fooObj) {

    //printf("debug -10\n");
    char buf[1024];
    printf("debug -9\n");
    memset(buf, 0x00, 1024);
    printf("debug -8\n");
    Foo_t* bar = (Foo_t*)buf;//malloc(sizeof(Foo_t));

    printf("debug -7\n");
    jclass clazz;
    printf("debug -6\n");
    jfieldID fid;
    printf("debug -5\n");

    //init the bar data of C
    char* t = "Yachun Miao";
    printf("Java_SendSMS_foo: %s %d\n", t, strlen(t));
    strcpy(bar->name, "Yachun Miao");
    printf("debug -4\n");
    bar->len = strlen(bar->name);

    printf("Java_SendSMS_foo: %s %d\n", bar->name, bar->len);

    printf("debug -3\n");
    // mapping bar of C to foo
    clazz = (*env)->GetObjectClass(env, fooObj);
    printf("debug -2\n");
    if (0 == clazz) {
        printf("debug -1\n");
        printf("GetObjectClass returned 0\n");
        return (-1);
    }
    printf("debug 0\n");
    fid = (*env)->GetFieldID(env, clazz, "len", "I");
    printf("debug 1\n");
    (*env)->SetLongField(env, fooObj, fid, bar->len);

    printf("debug 2\n");

    fid = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
    printf("debug 3\n");
    jstring name = (*env)->NewStringUTF(env, bar->name);
    printf("debug 4\n");
    (*env)->SetObjectField(env, fooObj, fid, name);
    printf("debug 5\n");


    //free(bar);
    return 0;
}

开发时,其他文件如下 sms.h

#ifndef _TX_SMS_H_
#define _TX_SMS_H_
#ifdef __cplusplu*
extern "C" {
    #endif
    typedef struct tagSmsEntry {
        int index;
        double text[40];
    } SmsEntry;
    int SmsInit(void);
    //无参数
    int SmsSend(char *phonenum, char *content);
    //指针变量参数
    int SmsRead(int x,SmsEntry *entry);

    //结构体参数
    #ifdef __cplusplus
}
#endif
#endif

sms.c

#include "sms.h" 
 int SmsInit(void) {
    printf("welcome \n");
    return 1;
}
int SmsSend(char *phonenum, char *content) {
    printf("liuxiao \n");
    char a[100];
    memset(a, 0x00, 100);
    memset(a, 0x31, 99);
    printf("%s\n",a);
    printf("%s %s\n",phonenum,content);
    return 2;
}
int SmsRead(int x,SmsEntry *entry) {
    int i;
    printf("mingxin\n");
    printf("%d \n",x);
    for (i=0;i<2;i++) {
        printf("%f ",entry->text[i]);
    }
    return 3;
}

注意通过经验总结发现,不能使用 malloc(sizeof(Foo_t))

使用之后,程序直接崩溃,所以只能使用临时数组,具体原因有待考究

 

4 生成动态库时点击 生成->生成解决方案 

 

linux 

1 生成库文件时,前面必须添加lib(感觉就是一xx操作)

2 安装java时,不要使用yum自带的安装,里面内容不全,没有include头文件,因此需要自己到官网下载

 具体指令如下 

mkdir usr/local/java
cd usr/local/java
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
tar -zxvf jdk-17_linux-x64_bin.tar.gz

然后就是修改 配置文件 追加 内容

JAVA_HOME=/usr/local/java/jdk-17.0.2
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME CLASSPATH PATH

最后 source /etc/profile

检验java -version

如果不对,就 which java 查看当前java 路径 再rm -rf 路径   此时,应该就可以看到版本号正确了

 

2 编译 注意 引入外部头文件时候 是大写的字母i 这个很坑,换成小写报错,只能大写,但是和小写字母L太像了注意 生成.so文件时,必须在文件前加上lib  不加将导致程序不识别(网上说了很多,但是没几个提到这一点的)

 

 

3 运行java程序时,   java -Djava.library.path=. SendSMS.java

 

 

相关代码如下

win vs2019 工程

https://files.cnblogs.com/files/RYSBlog/JCProtocol2.zip?t=1643077628

linux 

https://files.cnblogs.com/files/RYSBlog/linuxso.zip?t=1643077619

//

 

标签:封装,int,SendSMS,env,printf,debug,java,jni
来源: https://www.cnblogs.com/RYSBlog/p/15841958.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有