一:JAVA調用C++:
c++的setNetworkState方法實現:
<span style="font-size:18px;">#ifdef __cplusplus
extern "C" {
#endif
/*</span><pre name="code" class="cpp"><span style="font-size: 18px;"><span style="white-space:pre"> </span>setNetworkState</span><span style="font-family: Arial, Helvetica, sans-serif;">方法在java中的路徑</span><span style="font-size: 18px; font-family: Arial, Helvetica, sans-serif;">org/cocos2dx</span><span style="font-family: Arial, Helvetica, sans-serif; font-size: 18px;">/</span><span style="font-size: 18px; font-family: Arial, Helvetica, sans-serif;">cpp/</span><span style="font-size: 18px; font-family: Arial, Helvetica, sans-serif;">AppActivity中調用,其中</span><span style="font-family: Arial, Helvetica, sans-serif; font-size: 18px;">AppActivity是類名字和文件名字</span>
*/JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_setNetworkState(JNIEnv * env, jobject thiz, jint state){log("=========Java_org_cocos2dx_cpp_AppActivity_setNetworkState============> state = %d", state);g_networkstate = state;}#ifdef
__cplusplus}#endif
Java的寫法:
public class AppActivity extends Cocos2dxActivity {
public native void setNetworkState(int state);//聲明
@TargetApi(17)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 獲取網絡狀態
System.out.println("============獲取網絡狀態 01==========================");
IntentFilter netstatefilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
System.out.println("============獲取網絡狀態 02==========================");
BroadcastReceiver netstatereceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("============獲取網絡狀態 03==========================");
ConnectivityManager manager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
System.out.println("============獲取網絡狀態 04==========================");
manager.getActiveNetworkInfo();
System.out.println("============獲取網絡狀態 05==========================");
boolean etherconn = false;
boolean wificonn = false;
boolean mobileconn = false;
try {
NetworkInfo etherinfo = manager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
if (etherinfo.getState() == NetworkInfo.State.CONNECTED)
etherconn = true;
} catch (Exception e) {
}
try {
NetworkInfo wifiinfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (wifiinfo.getState() == NetworkInfo.State.CONNECTED)
wificonn = true;
}
catch (Exception e) {
}
try {
NetworkInfo mobileinfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mobileinfo.getState() == NetworkInfo.State.CONNECTED)
mobileconn = true;
} catch (Exception e) {
}
int state = 0;
if (etherconn)
state = 1;
else if (wificonn)
state = 2;
else if (mobileconn)
state = 3;
setNetworkState(state);//調用c++的
}
};
registerReceiver(netstatereceiver, netstatefilter);
}
}
二:Java調用C++
轉自:http://www.zaojiahua.com/using-jni.html
過程中要導入”Jni.h", 如果導入 "Jni.h"報錯,
把 C:\Program Files\Java\jdk1.8.0_25\include\jni.h
和 C:\Program Files\Java\jdk1.8.0_25\include\win32\jni_md.h
拷貝到
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include下
我的路徑是上面這個, 使用vs2013。你的路徑按你自己實際情況來操作。
jni的意思是java本地調用,通過jni可以實現java層代碼和其他語言寫得代碼進行交互。在cocos2d-x中,如果想要在c++層調用java層的代碼,就是通過jni技術。通過調用java層的代碼,我們就可以在Android平臺下實現一些引擎沒有提供給我們的功能,或者做一些其他的功能。比如加個廣告,加個分享,調用Android原生的對話框等等吧。Cocos2d-x比較人性化的是爲我們封裝了jni調用的一些接口,這個類就是JniHelper,我們只需要使用這個類提供給我們的接口就可以完成調用java層代碼的功能。先說一下這個類的位置,因爲自己在找的時候有點犯二,所以特意說明一下。在3.0和3.1以上的引擎版本中,這個類的位置分別如下。
3.1以後引擎把原來cocos目錄下的包含各個功能的文件夾都放到了cocos目錄下,我個人認爲這樣的放法還是比較好的。就是引擎老改目錄,希望以後不要放來放去了。最主要的當然是看看怎麼使用JniHelper這個類了。
首先使用之前要包含頭文件,寫法如下,記住要加上條件編譯,這個東西是Android平臺下纔用到。
1 |
#if(CC_TARGET_PLATFORM
== CC_PLATFORM_ANDROID) |
3 |
#include
"platform/android/jni/JniHelper.h" |
接着通過一小段代碼來說明一下這個類的用法。
1 |
#if(CC_TARGET_PLATFORM
== CC_PLATFORM_ANDROID) |
12 |
bool ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func1" , "()V" ); |
15 |
log ( "call
void func1() succeed" ); |
17 |
info.env->CallStaticVoidMethod(info.classID,info.methodID); |
大家書寫代碼的時候同樣需要將代碼使用條件編譯寫到裏面,JniMethodInfo是一個結構體,這個結構體的定義就是代碼中註釋掉的地方,然後使用JniHelper調用了靜態函數getStaticMethodInfo,從它的名字就知道這個函數的作用了,就是獲得java層中靜態函數的信息,這個信息保存在什麼地方呢,當然是JniMethodInfo中了,我們要獲取哪個類的哪個函數呢,第二個參數和第三個參數就是告訴JniHelper我們要獲取的是哪個函數的信息了,第二個參數是類文件的包名路徑,我在org/cocos2dx/cpp這個路徑下新建了一個類,叫做TestJni。其實前面的路徑就是一個包名,這裏使用的時候用/代替.。org的路徑當然就是我新建的這個工程的Android平臺目錄了。一會我要將這個項目打包然後測試一下,在eclipse下看看輸出。第三個參數當然就是方法名字了,第四個參數是需要注意的一個,有人把它叫做簽名,其實就是你要調用的java層函數的返回值和參數的類型說明。它把調用函數的參數寫到前面的括號中,返回值跟在括號的後邊,和我們平時書寫函數的時候正好相反了。那那個V是什麼東西呢,這個大寫字母就是對應的一個類型,如果是void類型,那麼就用一個V來代替,如果是一個int類型,那麼就用一個I代替,是不是很簡單,那其他的類型呢,如圖所示。
放了倆張表,用得時候查就好了,關於這個參數其他的細節問題待會討論。整個函數的返回值是一個bool類型,什麼意思不用說了吧。當這個函數的信息存在的時候我們就進入到了if中了,然後我使用了info結構體的第一個變量來調用了函數CallStaticVoidMethod,這個函數可真是需要說一說。首先它的調用者就是保存函數信息的結構體JniMethodInfo的第一個成員變量env,這貨是什麼東西不用管,用就好了。然後這個函數的第一個字母是大寫,這一點要小心,Call後邊如果跟Static代表的就是我要調用的是一個靜態的函數,如果沒有那就不是靜態的,不是靜態的函數,我們使用JniHelper獲取信息的時候用得就是getMethodInfo這個函數。然後Void代表的是函數的返回值,來看我們的例子,我調用的函數func1是一個無參無返回值的函數,這個看什麼地方,當然java代碼我接着會向你展示,但是你可以直接看getStaticMethodInfo這個函數的第四個參數啊。這裏的這個void代表的是函數的返回值類型,所以如果調用的是返回值爲int的java函數,那就是CallStaticIntMethod了。裏邊的參數就是結構體info的第二個和第三個成員變量了,代表的是類ID和函數ID。這樣的話基本的用法就說清楚了,接着就是TestJni中得代碼了,我把要調用到得函數都寫了出來。
1 |
package org.cocos2dx.cpp; |
3 |
import android.util.Log; |
7 |
public static void func1() |
9 |
Log.e( "xiaota" , "java:func1,called
succeed!" ); |
11 |
public static int func2() |
15 |
public static String
func3( int i) |
17 |
String
str = "get
int value:" +i; |
21 |
public static String
func4(String str) |
26 |
public static int func5( int a, int b) |
29 |
Log.e( "xiaota" , "func5" ); |
然後打包到Android平臺,我們使用USB連接上電腦,打開eclipse,進行調試,看看信息輸出了沒有。
好了,這樣的話就把這個流程都說明白了,下面我們看一些細節的地方。
1 |
#if(CC_TARGET_PLATFORM
== CC_PLATFORM_ANDROID) |
3 |
log ( "android
platform!" ); |
14 |
bool ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func1" , "()V" ); |
17 |
log ( "call
void func1() succeed" ); |
19 |
info.env->CallStaticVoidMethod(info.classID,info.methodID); |
23 |
ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func2" , "()I" ); |
26 |
log ( "call
int func2() succeed" ); |
28 |
jint
iret = info.env->CallStaticIntMethod(info.classID,info.methodID); |
29 |
log ( "func2的返回值是%d" ,iret); |
33 |
ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func3" , "(I)Ljava/lang/String;" ); |
36 |
log ( "call
int func3(int) succeed" ); |
38 |
jobject
jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID,1438); |
42 |
ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func4" , "(Ljava/lang/String;)Ljava/lang/String;" ); |
45 |
log ( "call
string func4(string) succeed" ); |
46 |
jobject
para = info.env->NewStringUTF( "haha" ); |
47 |
jstring
jstr = (jstring)info.env->CallStaticObjectMethod(info.classID,info.methodID,para); |
49 |
std::string
text = JniHelper::jstring2string(jstr); |
50 |
log ( "%s" ,text.c_str()); |
54 |
ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJni" , "func5" , "(II)I" ); |
57 |
log ( "call
int func5(int a,int b) succeed" ); |
58 |
jint
iret = info.env->CallStaticIntMethod(info.classID,info.methodID,1,2); |
59 |
log ( "return
value is %d" ,iret); |
上邊的代碼主要還是那倆個函數調用的說明,getStaticMethodInfo的第四個參數如果是類類型,注意要使用的簽名,後邊的分號也要加,如果參數有多個,直接連起來書寫就可以了。使用CallStaticMethod調用的時候注意一下參數和返回值的類型,傳遞參數的時候直接寫到函數的後邊,但是參數類型要正確,返回值使用對應的類型來接受,這個類型就是前面加一個j,比如java層返回的類型是int,那接受的類型就是jint,java層返回object,接受類型就是jobject。
以上是調用java的靜態函數,接下來是非靜態函數的調用。我將c++的代碼和java的代碼都貼出來。
2 |
bool ret
= JniHelper::getStaticMethodInfo(info, "org/cocos2dx/cpp/TestJniHelper" , "getObj" , "()Ljava/lang/Object;" ); |
7 |
log ( "call
static method" ); |
8 |
jobj
= info.env->CallStaticObjectMethod(info.classID,info.methodID); |
11 |
bool re
= JniHelper::getMethodInfo(info, "org/cocos2dx/cpp/TestJniHelper" , "func" , "()V" ); |
14 |
log ( "call
no-static method" ); |
16 |
info.env->CallVoidMethod(jobj,info.methodID); |
1 |
package org.cocos2dx.cpp; |
3 |
import android.util.Log; |
5 |
public class TestJniHelper |
7 |
private static TestJniHelper
instance = new TestJniHelper(); |
8 |
public static Object
getObj() |
14 |
Log.e( "xiaota" , "func
is called" ); |
因爲調用的是非靜態的函數,所以我們使用CallVoidMethod的時候就不能傳入類ID了,要傳入一個對象,告訴它調用的是哪個對象的方法,所以爲了有這麼一個對象,我們就得先調用一個靜態的方法來返回這個對象,然後用這個對象作爲參數調用非靜態函數。好了,關於Jni的基本用法就是這樣了,只是本人的一點拙見,沒有了解過的可以看看,如果是大神就繞路吧。