windows和linux环境下java调用C++代码-JNI技术
最近部门做安卓移动开发的需要调c++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结下,希望看到的以后能少走弯路。
使用工具:
1.java使用的ide为eclipse 2.windows环境下c++使用的ide为visual studio 2010 3.linux环境下c++使用的编译器为gcc/g++
一.windows环境下java调用c++代码
1.1新建java工程,生成相应头文件
eclipse新建工程名为"jnidemo"的java工程,在包名为com.woniu.native下新建"nativecpp.java"类,如下:
package com.woniu.native; public class nativecpp { public native void fun1(); public native int fun2(int a, int b); public native void fun3(string url1, string url2); }
编译生成.class文件
进入工程下的target\classes目录下,执行"javah -jni com.woniu.native.nativecpp",运行结果如下:
此时,会在classes目录下生成"com_woniu_native_nativecpp.h"头文件,头文件内容如下:
/* do not edit this file - it is machine generated */ #include <jni.h> /* header for class com_woniu_native_nativecpp */ #ifndef _included_com_woniu_native_nativecpp #define _included_com_woniu_native_nativecpp #ifdef __cplusplus extern "c" { #endif /* * class: com_woniu_native_nativecpp * method: fun1 * signature: ()v */ jniexport void jnicall java_com_woniu_native_nativecpp_fun1 (jnienv *, jobject); /* * class: com_woniu_native_nativecpp * method: fun2 * signature: (ii)i */ jniexport jint jnicall java_com_woniu_native_nativecpp_fun2 (jnienv *, jobject, jint, jint); /* * class: com_woniu_native_nativecpp * method: fun3 * signature: (ljava/lang/string;ljava/lang/string;)v */ jniexport void jnicall java_com_woniu_native_nativecpp_fun3 (jnienv *, jobject, jstring, jstring); #ifdef __cplusplus } #endif #endif
1.2 c++生成动态库
vs2010新建工程名为"jnidll"的win32控制台应用程序,win32应用程序向导界面选择 "dll"
创建完成后,把2.1中生成的"com_woniu_native_nativecpp.h"头文件放入该工程,并把头文件中的#include <jni.h>改为 "jni.h",
把jdk下include文件夹下的"jni.h"和include下win32文件夹下的"jni_md.h"头文件也一同放入创建的工程中。
工程目录如下:
编辑jnidll.cpp源码文件,实现头文件中的函数,如下:
/******************************************************** copyright (c), 2016-2017, filename: jni author: woniu201 email: wangpengfei.201@163.com created: 2017/09/20 description:jni function ********************************************************/ #include "stdafx.h" #include "com_woniu_native_nativecpp.h" #include "stdio.h" #include "stdlib.h" jniexport void jnicall java_com_woniu_native_nativecpp_fun1 (jnienv *, jobject) { printf("hello world\n"); } jniexport jint jnicall java_com_woniu_native_nativecpp_fun2 (jnienv *, jobject, jint a, jint b) { return a + b; } char* jstringtochar(jnienv* env, jstring jstr) { char* rtn = null; jclass clsstring = env->findclass("java/lang/string"); jstring strencode = env->newstringutf("gb2312"); jmethodid mid = env->getmethodid(clsstring, "getbytes", "(ljava/lang/string;)[b"); jbytearray barr = (jbytearray) env->callobjectmethod(jstr, mid, strencode); jsize alen = env->getarraylength(barr); jbyte* ba = env->getbytearrayelements(barr, jni_false); if (alen > 0) { rtn = (char*) malloc(alen + 1); memcpy(rtn, ba, alen); rtn[alen] = 0; } env->releasebytearrayelements(barr, ba, 0); return rtn; } jniexport void jnicall java_com_woniu_native_nativecpp_fun3 (jnienv *env, jobject, jstring url1, jstring url2) { //jstringתchar* char* purl1 = jstringtochar(env, url1); char* purl2 = jstringtochar(env, url2); printf("url1 = %s\n", purl1); printf("url2 = %s\n", purl2); }
我本机是64位系统,使用的是64位jdk,这里生成的动态库也要生成64位的库,否则调用的时候报如下错误:
更改vs编译生成64位dll,步骤如下:
编译生成解决方案,这时候会在工程根目录下,生成"x64文件夹",debug文件夹下会有动态库"jnidll.dll"
1.3 java调用dll
package com.woniu.jnidemo; import com.woniu.native.nativecpp; public class app { public static void main( string[] args ) { system.load("d:\\vs2010\\vc\\jnidll\\x64\\debug\\jnidll.dll"); nativecpp nativecpp = new nativecpp(); nativecpp.fun1(); system.out.println(nativecpp.fun2(3, 3)); nativecpp.fun3("www.baidu.com", "www.haoservice.cn"); } }
运行结果如下:
二:linux(centos)环境下java调用c++代码
2.1 编译环境
a.安装gcc和g++ yum install gcc-c++ b.安装jdk 去官网上下载jdk安装包,建议使用rpm安装包,会自动配置环境变量。安装完后如下:
本机的安装目录为:/usr/java/jdk1.8.0_144/,不同版本可能不同。
这里一定要注意不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件。
2.2 制作动态库(so库)
a.创建文件夹"jniso",mkdir jniso。 b.把2.1中生成的头文件"com_woniu_native_nativecpp.h"拷贝过来,#include "jni.h"改为#include <jni.h> c.新建jni.cpp源文件,添加如下代码:
#include <jni.h> #include "com_woniu_native_nativecpp.h" #include "stdio.h" #include "stdlib.h" #include "string.h" jniexport void jnicall java_com_woniu_native_nativecpp_fun1 (jnienv *, jobject) { printf("hello world\n"); } jniexport jint jnicall java_com_woniu_native_nativecpp_fun2 (jnienv *, jobject, jint a, jint b) { return a + b; } char* jstringtochar(jnienv* env, jstring jstr) { char* rtn = null; jclass clsstring = env->findclass("java/lang/string"); jstring strencode = env->newstringutf("gb2312"); jmethodid mid = env->getmethodid(clsstring, "getbytes", "(ljava/lang/string;)[b"); jbytearray barr = (jbytearray) env->callobjectmethod(jstr, mid, strencode); jsize alen = env->getarraylength(barr); jbyte* ba = env->getbytearrayelements(barr, jni_false); if (alen > 0) { rtn = (char*) malloc(alen + 1); memcpy(rtn, ba, alen); rtn[alen] = 0; } env->releasebytearrayelements(barr, ba, 0); return rtn; } jniexport void jnicall java_com_woniu_native_nativecpp_fun3 (jnienv *env, jobject, jstring url1, jstring url2) { char* purl1 = jstringtochar(env, url1); char* purl2 = jstringtochar(env, url2); printf("url1 = %s\n", purl1); printf("url2 = %s\n", purl2); }
d.编译,生成动态库
g++ -fpic -c jni.cpp -i /usr/java/jdk1.8.0_144/include/ -i /usr/java/jdk1.8.0_144/include/linux/
g++ -shared jni.o -o jni.so
2.3 java调用jni.so
import com.woniu.native.nativecpp; public class app { public static void main( string[] args ) { //windows环境下加载库 //system.load("d:\\vs2010\\vc\\jnidll\\x64\\debug\\jnidll.dll"); //linux下加载库 system.load("/mnt/hgfs/svn/svn/demo/jniso/jni.so"); nativecpp nativecpp = new nativecpp(); nativecpp.fun1(); system.out.println(nativecpp.fun2(3, 3)); nativecpp.fun3("www.baidu.com", "www.haoservice.cn"); } }
运行结果如下:
关注下面公众号,回复"105"获取windows下生成dll源码
关注下面公众号,回复"106"获取linux下生成so源码