把這幾天瞎搞的東西總結一下.
環境配置什么的也比較煩. ndk.java.在cocos2dx的環境中都有配置.參1
很基礎很基礎很基礎的環境配置.
1.android與C 之間的調用
android通過JNI 來調用C(不帶C++玩.extern "C"),
1.1android調用C
如果要在Eclipse中用C/C++編譯要在工程上選android tools 的add native support,來編譯c/c++.對於cocos2dx的理論上已經設置好了. 當然如果沒有. 那還是用cocos compile來編吧. 自己做的darkc項目的工程如果加上后會有問題. 可能是配置的原因 . 留個坑....
在src下com.example.wifiip包MainActivity.java文件中聲明C方法: native public void onBtnClick();
可以選擇用javah來把頭c的頭文件編譯出來,里面會有固定格式的函數聲明.
Run->Extern tools
嗯 , 具體 的參數 作用 不明. 留坑 ....后面還要用的javap用於簽名java函數.用於jni層c call java.如果明白規則 也可不用.主要是為了明確descriptor 同上
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class com_example_wifiip_MainActivity */ 4 5 #ifndef _Included_com_example_wifiip_MainActivity 6 #define _Included_com_example_wifiip_MainActivity 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: com_example_wifiip_MainActivity 12 * Method: onBtnClick 13 * Signature: ()V 14 */ 15 JNIEXPORT void JNICALL Java_com_example_wifiip_MainActivity_onBtnClick 16 (JNIEnv *, jobject); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
函數明是有規則的. 對照上面那個java文件,如果知道規則也可以不用生成.直接在寫個定義
在cpp文件中完成實現代碼.
android.mk文件中入相關的編譯文件和頭文件以及相應的指令. 參2
然后編譯跑就行了. 在java代碼中要調用
static { System.loadLibrary("wifiIP"); }
總是忘記....
其實不太難
1.2 c call java
只要在jni層的c/c++代碼中加入相應的代碼就可以了
調用靜態函數
// 獲取 MainActivity類,不是對象,對象已經有了是:objActivity jclass clsActivity = pJniEnv->FindClass("com/example/wifiip/MainActivity"); /// 獲取類中的函數 getWifiAddress的函數ID,第三個參數填寫該函數的函數簽名 jmethodID method = pJniEnv->GetMethodID(clsActivity, "getWifiAddress", "()I"); /// 調用java層函數 jobject object = pJniEnv->NewLocalRef(pJobject); int nIp = pJniEnv->CallIntMethod(object, method);
非靜態函數
long status; jclass cls; jmethodID mid; jint square; jboolean not; jobject jobj; cls = (*env)->FindClass(env, "com/example/hellojni/HelloJni"); if(cls !=0) { jmethodID construction_id = (*env)->GetMethodID(env, cls, "<init>", "()V"); if (construction_id ==0) { __android_log_print(ANDROID_LOG_INFO, "pvvvvvv_printStringJNi", "Result of construction_id== 0"); } jobject mTestProvider = (*env)->NewObject(env, cls, construction_id); mid = (*env)->GetMethodID(env, cls, "doLogin", "(ZZ)I"); if(mid !=0) { square = (*env)->CallIntMethod(env, mTestProvider, mid, JNI_TRUE, JNI_TRUE); __android_log_print(ANDROID_LOG_INFO, "pvvvvvv_printStringJNi ","doLogin %d" ,square); } }
這里有一個問題在於調用的android中的界面線程時要小心. 在調用的相關函數中Context context, 這個參數不能再傳this. 這地方坑我好久.因為實際上這里你是從外面調入. 不在一個線程中.就是空, 完全 不知道 你是誰啊.this毛線. 寫個靜態的存起this來或是傳入都可以.
實驗例子是:HelloJni.
2.lua與C 之間的調用
參3. 寫的十分詳細. 我就簡單寫下吧. 參4
c 與 lua 是利用棧 來交互的. 純C環境下的也實現. 都是基於cocos下的. 不用自己搞 環境 - -!
在cocos環境 lua調用C 需要把c函數注冊進lua中.
auto engine = LuaEngine::getInstance(); ScriptEngineManager::getInstance()->setScriptEngine(engine); LuaStack* stack = engine->getLuaStack(); stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA")); lua_State *L = stack->getLuaState(); lua_register(L, "test_lua_bind", test_lua_bind);
也可以通過ScriptEngineManager類從頭取得當前的LuaEngine對象,然后再getLuaStack()方法 得到封裝的LuaStack對象,再調用getLuaState()得到原始的lua_State結構指針。只要知道了入 口位置,其他一切就不成問題了,還是挺簡單的。
感興趣的話可以去看一下ScriptEngineManager類的詳細定義,在frameworks/cocos2d- x/cocos/base/CCScriptSupport.h文件中。
這個是直接注冊成一個全局函數 , 實際在dark工程中是注冊進名字空間中. 具體見工程....
2.2 c++調用lua
lua_State* pL = lua_open(); luaopen_base(pL); /* 執行腳本 */ luaL_dofile(pL, "helloLua.lua"); /* 把helloAdd函數對象放到棧中 */ lua_getglobal(pL, "helloAdd"); /* 把函數所需要的參數入棧 */ lua_pushnumber(pL, 10); lua_pushnumber(pL, 5); /* 執行函數,第一個參數表示函數的參數個數,第二個參數表示函數返回值個數 , Lua會先去堆棧取出參數,然后再取出函數對象,開始執行函數 */ lua_call(pL, 2, 1); int iResult = lua_tonumber(pL, -1);
依然是利用棧的方式 .
在cocos 環境下簡單的好多.
寫一個全局的方法.
auto luaStack = cocos2d::LuaEngine::getInstance()->getLuaStack(); lua_State* L = luaStack->getLuaState(); lua_getglobal(L, "onSdkInitCallBack"); /* query function by name, stack: function */ if (!lua_isfunction(L, -1)) { CCLOG("[LUA ERROR] name '%s' does not represent a Lua function", "onSdkInitCallBack"); lua_pop(L, 1); return; } luaStack->executeFunction(0);
3.android與lua之間的調用.
本來理解 lua 需要先調
static public void showAlertDialog(final String title, final String message, final int luaCallbackFunction) { s_instance.runOnUiThread(new Runnable() { @Override public void run() { doSdkLogin(false, true); AlertDialog alertDialog = new AlertDialog.Builder(s_instance).create(); alertDialog.setTitle(title); alertDialog.setMessage(message); alertDialog.setButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { s_instance.runOnGLThread(new Runnable() { @Override public void run() { Cocos2dxLuaJavaBridge.callLuaFunctionWithString(luaCallbackFunction, "xxxCLICKEDvvvxxx"); Cocos2dxLuaJavaBridge.releaseLuaFunction(luaCallbackFunction); } }); } }); alertDialog.setIcon(R.drawable.icon); alertDialog.show(); } }); }
用 c.再通過jni調用java 實際上這東西 已經在cocos下集成好了.luaj直接使用就可以了. 想想全是眼淚....
注意 GL線程. 和ui線程 之間的使用
4.cocos2d-x 3.0下綁定lua
綁定類進 參3里寫的很詳細....... 實在沒啥可總結的. 實際項目只是注冊函數進實現在. 一會818看有沒有他們自己注冊進去的類.
參考
1. http://jingyan.baidu.com/article/3ea51489e7a9bd52e61bbac7.html
2. http://blog.csdn.net/yili_xie/article/details/4906865
3. http://cn.cocos2d-x.org/tutorial/show?id=1295
4. http://blog.csdn.net/musicvs/article/details/8440707
5. http://blog.csdn.net/xdw1985829/article/details/6900155