windows和linux环境下java调用C++代码-JNI技术

来源:互联网 发布:易知资本 编辑:程序博客网 时间:2024/06/16 21:59

一.前言


最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结下,希望看到的以后能少走弯路。

使用工具:
1.JAVA使用的IDE为eclipse
2.windows环境下C++使用的IDE为visual studio 2010
3.linux环境下C++使用的编译器为gcc/g++

二.windows环境下java调用C++代码


2.1新建java工程,生成相应头文件

eclipse新建工程名为"jniDemo"的java工程,在包名为com.woniu.Native下新建"NativeCpp.java"类,如下:

[java] view plain copy print?
  1. package com.woniu.Native;  
  2.   
  3. public class NativeCpp {  
  4.     public native void fun1();  
  5.     public native int  fun2(int a, int b);  
  6.     public native void fun3(String url1, String url2);  
  7. }  



编译生成.class文件

进入工程下的target\classes目录下,执行"javah -jni com.woniu.Native.NativeCpp",运行结果如下:



此时,会在classes目录下生成"com_woniu_Native_NativeCpp.h"头文件,头文件内容如下:

[cpp] view plain copy print?
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_woniu_Native_NativeCpp */  
  4.   
  5. #ifndef _Included_com_woniu_Native_NativeCpp  
  6. #define _Included_com_woniu_Native_NativeCpp  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_woniu_Native_NativeCpp 
  12.  * Method:    fun1 
  13.  * Signature: ()V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1  
  16.   (JNIEnv *, jobject);  
  17.   
  18. /* 
  19.  * Class:     com_woniu_Native_NativeCpp 
  20.  * Method:    fun2 
  21.  * Signature: (II)I 
  22.  */  
  23. JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2  
  24.   (JNIEnv *, jobject, jint, jint);  
  25.   
  26. /* 
  27.  * Class:     com_woniu_Native_NativeCpp 
  28.  * Method:    fun3 
  29.  * Signature: (Ljava/lang/String;Ljava/lang/String;)V 
  30.  */  
  31. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3  
  32.   (JNIEnv *, jobject, jstring, jstring);  
  33.   
  34. #ifdef __cplusplus  
  35. }  
  36. #endif  
  37. #endif  


 

2.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源码文件,实现头文件中的函数,如下:

[cpp] view plain copy print?
  1. /******************************************************** 
  2. Copyright (C), 2016-2017, 
  3. FileName:   jni 
  4. Author:     woniu201 
  5. Email:      wangpengfei.201@163.com 
  6. Created:    2017/09/20 
  7. Description:Jni function 
  8. ********************************************************/  
  9. #include "stdafx.h"  
  10. #include "com_woniu_Native_NativeCpp.h"  
  11. #include "stdio.h"  
  12. #include "stdlib.h"  
  13.   
  14. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1  
  15.     (JNIEnv *, jobject)  
  16. {  
  17.     printf("hello world\n");  
  18. }  
  19.   
  20. JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2  
  21.     (JNIEnv *, jobject, jint a, jint b)  
  22. {  
  23.     return a + b;  
  24. }  
  25.   
  26. char* jstringToChar(JNIEnv* env, jstring jstr) {  
  27.     char* rtn = NULL;  
  28.     jclass clsstring = env->FindClass("java/lang/String");  
  29.     jstring strencode = env->NewStringUTF("GB2312");  
  30.     jmethodID mid = env->GetMethodID(clsstring, "getBytes""(Ljava/lang/String;)[B");  
  31.     jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);  
  32.     jsize alen = env->GetArrayLength(barr);  
  33.     jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  
  34.     if (alen > 0) {  
  35.         rtn = (char*) malloc(alen + 1);  
  36.         memcpy(rtn, ba, alen);  
  37.         rtn[alen] = 0;  
  38.     }  
  39.     env->ReleaseByteArrayElements(barr, ba, 0);  
  40.     return rtn;  
  41. }  
  42.   
  43. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3  
  44.     (JNIEnv *env, jobject, jstring url1, jstring url2)  
  45. {  
  46.     //jstringתchar*  
  47.     char* pUrl1 = jstringToChar(env, url1);  
  48.     char* pUrl2 = jstringToChar(env, url2);  
  49.     printf("url1 = %s\n", pUrl1);  
  50.     printf("url2 = %s\n", pUrl2);  
  51. }  

我本机是64位系统,使用的是64位JDK,这里生成的动态库也要生成64位的库,否则调用的时候报如下错误:



更改vs编译生成64位dll,步骤如下:






编译生成解决方案,这时候会在工程根目录下,生成"x64文件夹",Debug文件夹下会有动态库"JniDll.dll"



2.3 java调用dll

[java] view plain copy print?
  1. package com.woniu.jniDemo;  
  2.   
  3. import com.woniu.Native.NativeCpp;  
  4.   
  5. public class App   
  6. {  
  7.     public static void main( String[] args )  
  8.     {  
  9.         System.load("D:\\VS2010\\VC\\JniDll\\x64\\Debug\\JniDll.dll");  
  10.         NativeCpp nativeCpp = new NativeCpp();  
  11.         nativeCpp.fun1();  
  12.         System.out.println(nativeCpp.fun2(33));  
  13.         nativeCpp.fun3("www.baidu.com""www.haoservice.cn");  
  14.     }  
  15. }  

运行结果如下:




三.linux(CentOS)环境下java调用C++代码


3.1 编译环境

a.安装gcc和g++
  yum install gcc-c++

b.安装jdk
  去官网上下载jdk安装包,建议使用rpm安装包,会自动配置环境变量。安装完后如下:

  本机的安装目录为:/usr/java/jdk1.8.0_144/,不同版本可能不同。

  这里一定要注意不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件。


3.2 制作动态库(so库)

a.创建文件夹"jniso",mkdir jniso。

b.把2.1中生成的头文件"com_woniu_Native_NativeCpp.h"拷贝过来,#include "jni.h"改为#include <jni.h>

c.新建jni.cpp源文件,添加如下代码:

[cpp] view plain copy print?
  1. #include <jni.h>  
  2. #include "com_woniu_Native_NativeCpp.h"  
  3. #include "stdio.h"  
  4. #include "stdlib.h"  
  5. #include "string.h"  
  6.   
  7. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1 (JNIEnv *, jobject)  
  8. {  
  9.         printf("hello world\n");  
  10. }  
  11.   
  12. JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2  
  13.         (JNIEnv *, jobject, jint a, jint b)  
  14. {  
  15.         return a + b;  
  16. }  
  17.   
  18. char* jstringToChar(JNIEnv* env, jstring jstr) {  
  19.         char* rtn = NULL;  
  20.         jclass clsstring = env->FindClass("java/lang/String");  
  21.         jstring strencode = env->NewStringUTF("GB2312");  
  22.         jmethodID mid = env->GetMethodID(clsstring, "getBytes""(Ljava/lang/String;)[B");  
  23.         jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);  
  24.         jsize alen = env->GetArrayLength(barr);  
  25.         jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  
  26.         if (alen > 0) {  
  27.                 rtn = (char*) malloc(alen + 1);  
  28.                 memcpy(rtn, ba, alen);  
  29.                 rtn[alen] = 0;  
  30.         }  
  31.         env->ReleaseByteArrayElements(barr, ba, 0);  
  32.         return rtn;  
  33. }  
  34.   
  35. JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3  
  36.         (JNIEnv *env, jobject, jstring url1, jstring url2)  
  37. {  
  38.         char* pUrl1 = jstringToChar(env, url1);  
  39.         char* pUrl2 = jstringToChar(env, url2);  
  40.         printf("url1 = %s\n", pUrl1);  
  41.         printf("url2 = %s\n", pUrl2);  
  42. }  

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

3.3 java调用jni.so

[java] view plain copy print?
  1. import com.woniu.Native.NativeCpp;  
  2.   
  3. public class App   
  4. {  
  5.     public static void main( String[] args )  
  6.     {  
  7.         //windows环境下加载库  
  8.         //System.load("D:\\VS2010\\VC\\JniDll\\x64\\Debug\\JniDll.dll");  
  9.           
  10.         //linux下加载库  
  11.         System.load("/mnt/hgfs/svn/svn/Demo/jniso/jni.so");  
  12.           
  13.         NativeCpp nativeCpp = new NativeCpp();  
  14.         nativeCpp.fun1();  
  15.         System.out.println(nativeCpp.fun2(33));  
  16.         nativeCpp.fun3("www.baidu.com""www.haoservice.cn");  
  17.     }  
  18. }  

运行结果如下:




windows下生成dll源码地址:点击打开链接

linux下生成so动态库源码地址:点击打开链接
阅读全文
0 0