Java与C/C++互调用法(JNI调用第三方库)

在实际应用中,经常会有下面的情况。已经给出了由C/C++编译好的第三方动态链接库.dll文件,里面封装了一些我们要用的接口,并给出了接口相关的头文件,从中我们知道这些接口的参数类型和返回值类型,以方便我们调用这些接口。在Java应用中,有时为了某种需要,我们就必须要借助C/C++的动态链接库帮助我们完成我们要做的工作。这时JNI出现了,JNI(Java Native Interface)是由SUN提供的一套标准接口,供本地应用(C/C++)与JavaVM相互调用。

接下来就通过一个具体实例讲解JNI调用第三方动态库的用法。

一、准备工作:

由于手里面没有合适的第三方动态库可供调用,就自己手动封装了一些简单的函数接口,然后编译成动态链接库。实际应用中可能会提供已存在的动态链接库。下面就首先在VC中新建一个Win32项目BasicFunc——下一步——选择.dll 空项目 完成;新建头文件BasicFunc.h和源文件BasicFunc.cpp如下:

//BasicFunc.h:

double add(double a, double b);

double multiply(double a, double b);

double max(double a, double b);

 

//BasicFunc.cpp

#include <iostream>

using namespace std;

#ifdef __cplusplus

extern "C" {

#endif

   //__declspec(dllexport) is used to force generate function name as 'add

   //so you can find the address of this function by searching in the dll

   __declspec(dllexport)double add(double a, double b)

   {

       cout<< a << "与" << b<< "的和是:" << a + b << endl;

       returna + b;

   }

   __declspec(dllexport)double multiply(double a, double b)

   {

       cout<< a << "与" << b<< "的积是:" << a * b << endl;

       returna*b;

   }

   __declspec(dllexport)double max(double a, double b)

   {

       cout<< a << "与" << b<< "中较大者是:" << (a > b ? a : b)<< endl;

       return(a> b ? a : b);

   }

#ifdef __cplusplus

}

#endif

在VC中编译即可生成名为BasicFunc.dll的动态链接库。接下来我们就演示在Java中调用BasicFunc.dll中封装的接口的方法。

 

二、为了调用BasicFunc.dll中的接口函数,需要借助JNI来实现。在JNI中通过一个中介dll调用该接口。

1) 编写一个类,声明native方法

public class CallBasicFunc {

    public native voidCallBasicFuncAdd(double a,double b);

    public native doubleCallBasicFuncMul(double a,double b);

    static{

       System.loadLibrary("BasicFuncMediumDll");

    }

}

2)编译生成.h文件

cmd到CallThirdParty.java目录下,执行以下几个命令,生成.h文件。(需要设定java环境变量)

第一步:javac  CallBasicFunc.java 生成CallBasicFunc.class

第二步:Javah –jni CallBasicFunc生成CallBasicFunc.h头文件

内容如下:

/* DO NOT EDIT THISFILE - it is machine generated */

#include <jni.h>

/* Header for classCallBasicFunc */

 

#ifndef _Included_CallBasicFunc

#define _Included_CallBasicFunc

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:    CallBasicFunc

 * Method:   CallBasicFuncAdd

 * Signature: (DD)V

 */

JNIEXPORT void JNICALL Java_CallBasicFunc_CallBasicFuncAdd

  (JNIEnv *, jobject, jdouble, jdouble);

 

/*

 * Class:    CallBasicFunc

 * Method:   CallBasicFuncMul

 * Signature: (DD)D

 */

JNIEXPORT jdouble JNICALL Java_CallBasicFunc_CallBasicFuncMul

  (JNIEnv *, jobject, jdouble, jdouble);

 

#ifdef __cplusplus

}

#endif

#endif

3)创建C/C++工程,工程名为BasicFuncMediumDll,将上一步生成的头文件复制并添加到当前工程,添加源文件CallBasicFunc.cpp,在其中实现CallBasicFuncAdd ()和CallBasicFuncMul()方法.内容如下:

#include<Windows.h>

#include<iostream>

#include"CallBasicFunc.h"

using namespace std;

 

#ifdef __cplusplus

extern "C" {

#endif

 

typedef double (*ThirdPartyFunc)(double, double);

 

JNIEXPORT void JNICALL Java_CallBasicFunc_CallBasicFuncAdd

(JNIEnv *env, jobject obj, jdouble arg_a, jdouble arg_b)

{

    HMODULE dlh = NULL;

    ThirdPartyFunc thirdPartyFunc=NULL;

    if (!(dlh = LoadLibrary(L"BasicFunc.dll")))

    {

       printf("LoadLibrary() failed: %d\n", GetLastError());

    }

 

    double a = arg_a;

    double b = arg_b;

 

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"add")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "a+b="<< (*thirdPartyFunc)(a, b) << endl;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"multiply")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "a*b="<< (*thirdPartyFunc)(a, b) << endl;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"max")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "Bigger of a and b is: " << (*thirdPartyFunc)(a, b) << endl;

    //thirdPartyFunc= NULL;

 

}

 

JNIEXPORT jdouble JNICALL Java_CallBasicFunc_CallBasicFuncMul

(JNIEnv *env, jobject obj, jdouble arg_a, jdouble arg_b)

{

    double a = arg_a;

    double b = arg_b;

    HMODULE dlh = NULL;

    ThirdPartyFunc thirdPartyFunc = NULL;

    if (!(dlh = LoadLibrary(L"BasicFunc.dll")))

    {

       printf("LoadLibrary() failed: %d\n", GetLastError());

    }

    jdouble result;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"multiply")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    result = (*thirdPartyFunc)(a, b);

    cout << "有返回值的本地方法a*b=" << result<< endl;

    return result;

}

#ifdef __cplusplus

}

#endif

4)Build这个工程,生成BasicFuncMediumDll.dll动态链接库

5)编写测试java程序Test.java,调用以上生成的dll库。如下:

public class Test {

     public static void main(String[]args) {      

     CallBasicFunccallThirdParty = new CallBasicFunc();

    callThirdParty.CallBasicFuncAdd(10.3, 4.8);   

         //System.out.println("两数之和是:"+res);

     System.out.println("Java中调用有返回值的本地方法"+callThirdParty.CallBasicFuncMul(34.2, 5.48));

     }   

}

输出结果:

10.3与4.8的和是:15.1

a+b=15.1

10.3与4.8的积是:49.44

a*b=49.44

10.3与4.8中较大者是:10.3

Bigger of a and b is: 10.3

34.2与5.48的积是:187.416

有返回值的本地方法a*b=187.416

Java中调用有返回值的本地方法187.41600000000003

 

这里没有演示C/C++调用Java的情况,C/C++调用Java即是在本地方法中访问Java类的成员属性和成员方法。这里需要进一步的了解JNI对操作属性和方法的用法。以后再进一步研究。

注意:没有配置环境变量的情况下,需要将第三方动态库copy到C/C++工程BasicFuncMediumDll的根目录下,将BasicFuncMediumDll.dll copy到windows的System32目录或JDK的bin目录下。

由于本人也是初次接触JNI,如有不正确的地方,还望各位大牛不吝赐教,予以指正!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,可以使用WebView中JavaScript与Android中Java方法互调。 想要实现这个功能,需要使用到Android中的WebView的addJavascriptInterface方法。这个方法可以将Java对象暴露给JavaScript代码,JavaScript代码就可以调用这个对象的方法,实现JavaJavaScript的互通。 具体步骤如下: 1. 在Java代码中创建一个类,这个类中包含需要暴露给JavaScript的方法。 2. 使用WebView的addJavascriptInterface方法将这个Java类对象暴露给JavaScript。 3. 在JavaScript代码中,使用window对象来访问这个Java对象,即可调用其中的方法。 具体的实现可以参考下面的代码示例: Java代码: ```java public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } } ``` 在Activity中使用addJavascriptInterface方法将Java对象暴露给JavaScript: ```java WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android"); ``` JavaScript代码中通过window对象访问Java对象: ```javascript function showToast() { Android.showToast("Hello World!"); } ``` 注意,addJavascriptInterface方法需要在主线程中调用,否则可能会出现安全问题。另外,在使用JavaScript调用Java方法时,需要添加@JavascriptInterface注解,以确保安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值