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動態庫