1. 程式人生 > >c++呼叫java

c++呼叫java

通過JNI獲取Java虛擬機器,再獲取當前程式的JNI環境,通過JNI環境獲取需要呼叫的java類資訊,再獲取需要呼叫的java類中的函式資訊。再通過JNI環境呼叫,使用類資訊、函式資訊,呼叫對應的java函式。
看起來好像有點複雜,but不用擔心,cocos2d-x中有一個JniHelper類(標頭檔案的copyright為:cocos2d-x.org,是Google提供的還是cocos2d-x小組自己封裝的我就不清楚了),它已經把這些工作封裝好了。

JniHelper類的使用

加入如下標頭檔案:

#include "platform/android/jni/JniHelper.h"

需要使用的介面如下:

static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);

實現上我們只需要使用上面這兩個介面,就可以獲取java類的所有函式資訊了。JNI環境的獲取、各種錯誤處理都已經在這兩個介面實現中封裝好了。
先上程式碼,再來依次講解每個引數的意義和使用方法:

    //函式資訊結構體
    JniMethodInfo minfo;
    bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/
                                                 "com/omega/MyApp",/*類的路徑*/
                                                 "getJavaActivity",/*函式名*/
                                                 "()Ljava/lang/Object;");/*函式型別簡寫*/
    jobject activityObj;
    if (isHave)
    {
        //CallStaticObjectMethod呼叫java函式,並把返回值賦值給activityObj
        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
    }

OK,很簡單。上面的程式碼,就是使用JNI在C++中呼叫java類靜態函式的典型使用方法。只有兩步:

  • 1. 獲取java函式的資訊,classid、methodid等等
  • 2. 選擇JNIEnv中的介面,進行函式呼叫

getStaticMethodInfo引數詳解

兩個介面的引數一樣,意義也相同,詳解如下:
JniMethodInfo &methodinfo JniMethodInfo物件的引用,函式執行中會把jniEvn、classid、methodid寫入到引用中。
const char *className 類的路徑,把類的完整包名寫全,用法如以上程式碼。
const char *methodName 函式名,函式名寫上就行了。

const char *paramCode 函式型別簡寫
這個引數需要單獨介紹,它的格式為:(引數)返回型別。
例如:無引數,void返回型別函式,其簡寫為 ()V
java中的型別對應的簡寫如下:

引數型別 引數簡寫
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
Object Ljava/lang/String; L用/分割類的完整路徑
Array [Ljava/lang/String; [簽名 [I

多引數的函式
如果函式有多個引數,直接把簡寫並列即可。注意Object與Array型引數簡寫結尾的分號,示例:
IIII //4個int型引數的函式
ILjava/lang/String;I //整形,string型別,整形組合 (int x, String a, int y)

通過JNIEnv進行函式呼叫

JNIEvn有一系列的CallStatic[返回型別]Method、Call[返回型別]Method介面,需要針對不同的函式返回型別選擇呼叫。
[返回型別]以函式返回型別的不同,對應不同的函式名。
例如:
CallStaticVoidMethod ———void
CallVoidMethod ———void
其對應關係如下:

函式名 函式返回值型別
Void void
Object jobject
Boolean jboolean
Byte jbyte
Char jchar
Short jshort
Int jint
Long jlong
Float jfloat
Double jdouble

引數傳遞
呼叫有引數的java函式時,需要把對應的引數傳遞進去。需要把引數按順序加入到classid、methodid後面,並且需要做型別轉換。例如:

jint jX = 10;
jint jY = 10;
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jX, jY);

引數型別轉換關係如下:

C++型別 JAVA型別
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
Object jobject
Class jclass
String jstring
Object[] jobjectArray
boolean[] jbooleanArray
byte[] jbyteArray
char[] jcharArray
short[] jshortArray
int[] jintArray
long[] jlongArray
float[] jfloatArray
double[] jdoubleArray

string型別的轉換
實際上我們最常用的引數型別,主要是內建的資料型別、string字串型別。資料型別可以直接轉為j型別,但是string型別需要做如下處理:

jstring jmsg = minfo.env->NewStringUTF("http://www.baidu.com");
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jmsg);

非靜態函式的呼叫

非靜態函式的呼叫與靜態函式的呼叫型別,但是需要通過一個靜態函式獲取java類物件。
示例:

//C++程式碼
    //1. 獲取activity靜態物件
    JniMethodInfo minfo;
    bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                 "com/omega/MyApp",
                                                 "getJavaActivity",
                                                 "()Ljava/lang/Object;");
    jobject activityObj;
    if (isHave)
    {
        //呼叫靜態函式getJavaActivity,獲取java類物件。
        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
    }

    //2. 查詢displayWebView介面,獲取其函式資訊,並用jobj呼叫
    isHave = JniHelper::getMethodInfo(minfo,"com/omega/MyApp","displayWebView", "(IIII)V"); 

    if (!isHave)
    {
        CCLog("jni:displayWebView 函式不存在");
    }
    else
    {
        //呼叫此函式
        jint jX = (int)tlX;
        jint jY = (int)tlY;
        jint jWidth = (int)webWidth;
        jint jHeight = (int)webHeight;
        //呼叫displayWebView函式,並傳入引數
        minfo.env->CallVoidMethod(activityObj, minfo.methodID, jX, jY, jWidth, jHeight);
    }

詳盡的示例程式碼

最後,放一塊比較詳細的JNI使用程式碼,基本上覆蓋了的全部使用情況。

    JniMethodInfo minfo;//JniHelper   

    /* 測試用方法 */ 
    /*bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","loginGree", "()V"); //
     if (isHave) {
     //CCLog("有showText ");
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID);
     }else
     {
     //CCLog("沒有方法showText");
     }*/

    /* 分享 */
    /*//將c++中的string轉換成java中的string
     //char str[] = "test";
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","shareSina", "(Ljava/lang/String;Ljava/lang/String;)V"); //
     if (isHave) {
     //CCLog("有share ");
     jstring jstr = minfo.env->NewStringUTF("test1 share");
     jstring jst = minfo.env->NewStringUTF("/data/data/com.cocoa/cy.png"); 
     //jstring jst = minfo.env->NewStringUTF("");
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,jstr,jst);
     }else
     {
     //CCLog("沒有方法share");
     }*/
    /* 設定高分 */
    /*jint ind = 0;
     jlong lsre = 2202l;
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","setHighScore", "(IJ)V"); 
     if (isHave) {
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,ind,lsre);            
     }*/
    /* 成就解鎖 */
    /*jint aind = 0;
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","unLock", "(I)V"); 
     if (isHave) {
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,aind);            
     }*/
    /* 測試用方法 */ 
    bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","rtnActivity","()Ljava/lang/Object;");
    jobject jobj;
    if (isHave) { 
        jobj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); 
    }       
    //CCLog(" jobj存在"); 
    /* 測試用方法,非靜態無引數無返回值方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "()V"); 
     if (isHave) {
     minfo.env -> CallVoidMethod(jobj,minfo.methodID);
     }*/
    /* 測試用方法,非靜態有java型別的String引數無返回值方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;)V"); 
     if (isHave) {
     jstring jmsg = minfo.env->NewStringUTF("msg okey!");
     minfo.env -> CallVoidMethod(jobj,minfo.methodID,jmsg);
     }*/
    /* 測試用方法,返回java型別的String,有java型別的String和int引數方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;I)Ljava/lang/String;"); 
     if (isHave) {
     jstring jmsg = minfo.env->NewStringUTF("msg okey! return string");
     jint index = 0;
     minfo.env -> CallObjectMethod(jobj,minfo.methodID,jmsg,index);
     }*/
    /* 測試用方法,返回java型別的String[],有java型別的String[]和int引數方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "([Ljava/lang/String;I)[Ljava/lang/String;"); 
     if (isHave) {
     jobjectArray args = 0;
     jstring str;
     jsize len = 5;
     const char* sa[] = {"Hi,","World!","JNI ","is ","fun"};
     int i = 0;
     args = minfo.env->NewObjectArray(len,minfo.env->FindClass("java/lang/String"),0);
     for(i=0;iNewStringUTF(sa[i]);
     minfo.env->SetObjectArrayElement(args,i,str);
     }
     //minfo.env->GetStringArrayRegion(args,0,10,buf);
     //jintArray jmsg = {1,2,3};
     //minfo.env->NewStringUTF("msg okey! return string");
     jint index = 0;
     minfo.env -> CallObjectMethod(jobj,minfo.methodID,args,index);
     }*/
    /* 測試用方法,無返回型別,有java型別的int[]和int引數方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([II)V"); 
     if (isHave) {
     jint buf[]={7,5,8,9,3};
     jintArray jintArr; //定義jint陣列
     jintArr = minfo.env->NewIntArray(5);
     minfo.env->SetIntArrayRegion(jintArr,0,5,buf);
     jint index = 0;
     minfo.env -> CallVoidMethod(jobj,minfo.methodID,jintArr,index);
     }*/
    /* 測試用方法,無返回型別,有java型別的byte[]和int引數方法 */
    isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([BI)V"); 
    if (isHave) {
        jbyte buf[]={7,5,8,9,3};
        jbyteArray jbyteArr; //定義jbyte陣列
        jbyteArr = minfo.env->NewByteArray(5);
        minfo.env->SetByteArrayRegion(jbyteArr,0,5,buf);
        jint index = 0;
        minfo.env -> CallVoidMethod(jobj,minfo.methodID,jbyteArr,index);
    }
private static HiWorld hiWorld = null;
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    hiWorld = this;
    if (detectOpenGLES20()) {
        // get the packageName,it's used to set the resource path
        String packageName = getApplication().getPackageName();
        super.setPackageName(packageName);
        // set content
        setContentView(R.layout.game_demo);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
                                  R.layout.window_title);

        mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.game_gl_surfaceview);
        mGLView.setTextField((Cocos2dxEditText) findViewById(R.id.textField));
        mGLView.setEGLContextClientVersion(2);
        mGLView.setCocos2dxRenderer(new Cocos2dxRenderer());
        task = new TimerTask() {
            @Override
            public void run() {
                // HiWorld.shoot(hiWorld);
                Log.e("-------------------", "-------------------");
                // 呼叫c++中的方法
                System.out.println("------------------------"
                                   + stringZjy1());
            }
        };
        timer = new Timer();
        timer.schedule(task, 5000);
    } else {
        Log.d("activity", "don't support gles2.0");
        finish();
    }

    static {
        System.loadLibrary("game");
    }

    // c++中呼叫的方法
    public static Object rtnActivity() {
        System.out.println("----------rtnActivity");
        return hiWorld;
    }

    // c++中呼叫的方法,傳String型別
    public void showText(final String msg) { 
        // 新增到主執行緒
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------msg:"+msg);
            }
        });
    }
    //c++中呼叫的方法,傳String型別和int型別
    public String showText(final String msg,final int index) { 
        // 新增到主執行緒
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------msg:"+msg+"; index="+index);
            }
        });
        return "okey String showText(final String msg,final int index)";
    }
    //c++中呼叫的方法,傳String[]型別和int型別
    public String[] showText(final String[] msg,final int index) { 
        String[] strArr = {"1","2","3","4","5"};
        // 新增到主執行緒
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                for(String _str:msg){
                    System.out.println("----------String[] msg:"+_str+"; index="+index);
                }
            }
        });
        return strArr;
    }
    //c++中呼叫的方法,傳int[]型別和int型別
    public void testArr(final int msg[],final int index) { 
        // 新增到主執行緒
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------int[] msg len:"+msg.length);
                for(int _bl:msg){
                    System.out.println("----------int[] msg:"+_bl+"; index="+index);
                }
            }
        });
    }
    //c++中呼叫的方法,傳int[]型別和int型別
    public void testArr(final byte msg[],final int index) { 
        // 新增到主執行緒
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------byte[] msg len:"+msg.length);
                for(int _bl:msg){
                    System.out.println("----------byte[] msg:"+_bl+"; index="+index);
                }
            }
        });
    }

相關推薦

JNI之 c/c++呼叫java建構函式

有時候c/c++是面向過程編碼,很多有用工具類都沒有,要編碼人員自己實現,如果可以呼叫java大量存在的類豈不是更省事更簡潔。 下面是通過呼叫java的Date類產生是時間戳。 public class JniConsTest { //c訪問java建構函式,並返回物件

JNI-通過C++呼叫JAVA

1、背景     在Report_Center_Task_Proc上報訊息執行緒中,我們在訊息佇列裡面獲取到資料後,把資料簡單解析後通過java介面g_jniEnv->CallVoidMethod上報資料,那什麼在c++程式碼中怎麼呼叫java函式方法的呢? &nb

C#呼叫JAVA封裝的DLL

一、將已經編譯後的java中Class檔案進行打包;打包命令JAR如:將某目錄下的所有class資料夾全部進行打包處理;使用的命令:jar cvf test.jar -C com/ . //注意這裡最後為 空格加點( .) 切記其中test.jar為要生成的jar包;com/ . 為指定的當前目錄下的資料夾,

android jni開發中c++ 呼叫java 方法

    最近幾天搞fbreader 電子書的二次開發,其中需要 c++ 呼叫 java方法解密電子書,所以l老虎吃天,硬著頭皮看c++程式碼。  具體的思路如下,其實也就這幾步:      1. jni 中用到 java反射的方法

Android-NDK學習記錄4-C呼叫Java靜態方法修改靜態欄位

一. jni互動相關-方法簽名 方法簽名在jni的使用中經常都會用到,在java中會有過載,那麼定位到一個方法的方式:類+方法名稱+方法簽名,那麼我們先學習下簽名規則: 基本型別簽名: 咱們基本型別有各自的簽名,如下表 型別名

Android JNI-c/c++呼叫java方法

在使用ndk開發的時候,java呼叫c/c++方法是必須要的。但是很多時候,c/c++有callback需要反饋給java的時候(比如IM通訊登入成功資訊和一些異常資訊),就需要c/c++呼叫java方法了。 在看這篇文章之前,必須對JNI有一些基礎的瞭解,比

Android JNI 通過C/C++呼叫JAVA方法

#include "video1_TestNative.h"   #include <iostream>  using namespace std;   JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, job

Linux下C++呼叫Java簡單例項(jni)

假設工作目錄為/home1. Java端1)  mkdir leixf && cd leixf2) 建立SubClass.java檔案,內容如下:package leixf;public class SubClass {private String name

JNI進階一 (C++呼叫java屬性和方法,javap的使用)

一、C/C++函式分析://獲取jclass物件,引數:this的意思,就是native方法所在的類1.GetObjectClass(jobject) //獲取普通屬性id,第一個引數:類物件, 第二個引數:屬性名,第三個引數:屬性簽名(不知道的同學點選這裡)2.GetFie

c/c++呼叫JAVA

JNI允許您從本機程式碼內呼叫 Java 類方法。要做到這一點,通常必須使用 Invocation API 在本機程式碼內建立和初始化一個 JVM。下列是您可能決定從 C/C++ 程式碼呼叫Java 程式碼的典型情況:    1.希望實現的這部分程式碼是平臺無關的,它將用於跨

Android Studio3.0開發JNI流程------Java呼叫C++以及C++呼叫Java

上一章講解了JNI中一些函式表的說明,這節開始講解Java與C++互調的過程。 在Android Studio3.0中建立一個支援JNI開發的Android程式。 編寫activity_main.xml佈局: <?xml version="1.0

c#呼叫java的Servlet/Controller/Action實現應用間無縫呼叫

               現代企業資訊化在有了一定的基礎之後,大部分企業都會意識到資料孤島,什麼是資料孤島呢?就是各個系統的資料庫相互獨立,各個系統各自建立各自的基礎資料等相關資訊,系統資訊量維護大,重複勞動較多,基礎資料維護困難,在出去相關報表的時候,資料對應困難,無

C呼叫java例子

實驗程式碼已打包,下載地址。實現原理:使用JNI提供的介面來反射得到Java方法,進行呼叫。jni.h在JDK裡(jdk1.8.0_121/include/)。(通過JNI可以實現java呼叫C,也可以實現C呼叫java) HelloWorld.java:public cla

JNI開發-C/C++呼叫Java函式傳遞多個引數

       C/C++呼叫Java函式傳遞多個引數並返回String型別; Java的CCallJavaTools類: package com.niubashaoye.ndk.jni; public class CCallJavaTools { /** * C

c++呼叫java

通過JNI獲取Java虛擬機器,再獲取當前程式的JNI環境,通過JNI環境獲取需要呼叫的java類資訊,再獲取需要呼叫的java類中的函式資訊。再通過JNI環境呼叫,使用類資訊、函式資訊,呼叫對應的java函式。 看起來好像有點複雜,but不用擔心,cocos2d-x中有

【JNI開發】C++呼叫java函式的實現方法

本文的主要內容:C++中呼叫java類的成員函式和靜態成員函式 1,java程式碼 public class SNaviEngineManager { public void sendMe

JNI c呼叫Java 返回值為String

Java定義: public String getSignatureInfo() { try { PackageInfo packageInfo = mContext.getPackageManager().getPack

Hessian學習之(一):簡單測試 + C#呼叫Java服務

開始調研Hessian和Mina,目的是希望能夠建立一個簡單的“高效能分散式服務呼叫框架”!類似於Dubbo或者淘寶的HSF那種,但是是要跨平臺的,而不僅僅侷限在Java領域。 hessian是一種遠端呼叫的機制(RPC) ,類似於web service,不過它是使用自己

Jni程式設計(二)jni.h 標頭檔案定義分析,以及c/c++呼叫java類的屬性和方法

在第一篇部落格中 我們初步瞭解了jni程式設計的步驟,那接下來我認為極其重要的事情是搞清楚jni.h標頭檔案裡面的結構,包括資料型別和方法的定義等,這些是必須的,否則沒有辦法進行學習,就像寫文章一樣,要先學會寫字是一樣的道理。 首先來看一下jni.h標頭檔案的組成:ps下面

jni 開發 c呼叫java

上一篇文章是java如何呼叫c ,這篇文章是c如何呼叫 java  c呼叫java一共分為5步: 1:編寫java native方法 2生成對應的標頭檔案 3複製標頭檔案到visule studio中 4查詢方法和屬性的簽名,實現native方法 5編譯生成.dll動態庫