您的位置:首页 > 编程语言 > C语言/C++

JAVA通过JNI调用C语言库

2018-03-20 18:00 176 查看
重点内容##1.前言

- JDK版本1.8.0

- 操作系统 ubuntu 16.04.2

- 目标实现JAVA调用C语言库

root@msos:/root# java -version
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)


2.JNI层说明

2.1.C语言的JNI封装例程

# define MSAUTHENTJNI_C
# include <libmscommon/mscommon.h>
# include <libmslog/mslog.h>
# include "jni.h"
# include "msauthent.h"

# define FLAG  "msauthentjni"

JNIEXPORT void JNICALL Java_jniTest_msauthentjni_init( JNIEnv * env,jobject thiz,jint logopt)
{
msauthent_oneapi_init(logopt);
}

JNIEXPORT jint JNICALL Java_jniTest_msauthentjni_getconnect( JNIEnv * env,jobject thiz, jstring product_num,jint debug)
{
const char* pstr = (*env)->GetStringUTFChars(env,product_num, ms_null);
ms_bufcheckret(-1, pstr);
int connect=msauthent_oneapi_getconnect(pstr,debug);
(*env)->ReleaseStringUTFChars(env,product_num, pstr);
return  connect;
}

JNIEXPORT void JNICALL Java_jniTest_msauthentjni_deinit( JNIEnv * env,jobject thiz)
{
msauthent_oneapi_deinit();
}

# undef MSAUTHENTJNI_C


2.2.编译命令

gcc  src/msauthentjni.c  -DOS_LINUX_X64 -Isrc `pkg-config --cflags libmslog` `pkg-config --cflags libmscommon` `pkg-config --cflags libmstool` `pkg-config --libs libmslog` `pkg-config --libs libmscommon` `pkg-config --libs libmstool` -shared -fPIC -I/usr/lib/jdk/jdk1.8.0_161/include -I/usr/lib/jdk/jdk1.8.0_161/include/linux  `pkg-config --libs libmsauthent` `pkg-config --cflags libmsauthent`  -o out/lib/libmsauthentjni.so


2.3.格式类型说明

JNI函数固定格式

JNIEXPORT  返回值类型   JNICALL java_package_class_nativeapi( JNIEnv * env,jobject thiz,其他参数) ;


java_package_class_nativeapi的格式

“Java_jniTest_msauthentjni_init”中package为jniTest,class为msauthentjni,而nativeapi为init,即这个函数只能被包名为jniTest中的msauthentjni(class)调用,且函数名为init;(类似的还有Java_jniTest_msauthentjni_getconnect,Java_jniTest_msauthentjni_deinit)


( JNIEnv * env,jobject thiz,其他参数)的格式:前两个参数必须存在,需要传递的其他参数可扩展;

JNI类型映射不做过多的描述,只列举几个常用的

Java        JNI             C/C++
boolean     jboolean        8位整型
byte        jbyte           带符号的8位整型
char        jchar           无符号的16位整型
short       jshort          带符号的16位整型
int         jint            带符号的32位整型
long        jlong           带符号的64位整型
float       jfloat          32位浮点型
double      jdouble         64位浮点型
String      jstring         字符串对象


2.4.特别注意

如果传入的参数是jstring类型,必须要进行转换,转换代码参考函数Java_jniTest_msauthentjni_getconnect中的product_num;

如果返回值是jstring类型,需要调用(*env)->NewStringUTF(env,tmpstr)进行转换;

如果希望传递object,那么可以借助jobject thiz这个参数,这里不再详解;

3.JAVA层说明

3.1.JAVA语言调用的JNI例程

package jniTest;
public class msauthentjni {
static {
System.loadLibrary( "msauthentjni" );
}
public static native void  init( int logopt);
public static native int   getconnect(String product_num,int debug);
public static native void  deinit();
public static void main(String[] args) {
init(54);
System.out.print("------------connect:"+getconnect("MS-EDUECC",1));
deinit();
}
}


3.2.说明

库的加载使用System.loadLibrary( “msauthentjni” ),只需要加载最直接的库即可;

对于nativeapi为init的调用,完全吻合2.3所述

4. 错误列表

4. 1.环境错误,错误信息如下

`Exception in thread "main" java.lang.UnsatisfiedLinkError: no msauthentjni in java.library.path`
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
`at jniTest.msauthentjni.<clinit>(msauthentjni.java:5)`


问题原因:libmsauthentjni.so库不在ECLIPSE的标准库路进下;

解决方法:将libmsauthentjni.so的库路径(我的是/usr/local/lib/)加入到环境变量LD_LIBRARY_PATH,然后再其中ECLIPSE程序。

`export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:/usr/local/lib/`


4. 2.JNI函数名错误,错误信息如下

`Exception in thread "main" java.lang.UnsatisfiedLinkError: jniTest.msauthentjni.init(I)V
at jniTest.msauthentjni.init(Native Method)
at jniTest.msauthentjni.main(msauthentjni.java:15)`


问题原因:jni函数名中的包名或者CLASS和调用的不匹配,详细见本文2.3描述;

解决方法:修改jni函数名中的包名或者CLASS
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: