唉,首先說點閑話 – -。Himi搞了不短的時間,這個問題一直沒有解決,最後終于在張大(cocos2dx引擎開發者之一 張小明)的指導下解決了此問題。
在進入正文之前,講解下一些基礎知識:(目前Himi的版本是cocos2xx 2.1.2 hotfix)
第一部分:
編譯過項目到Android的童鞋們肯定知道建立好的Android項目下的jni下的Android.mk 這個檔案,如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := game_shared
LOCAL_MODULE_FILENAME := libgame
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_STATIC_LIBRARIES := curl_static_prebuilt
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_lua_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_extension_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,cocos2dx)
$(call import-module,CocosDenshion/android)
$(call import-module,scripting/lua/proj.android/jni)
$(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl)
$(call import-module,extensions)
這個檔案中,主要我們關注如下幾個配置:‘
1. LOCAL_SRC_FILES : 編譯到Android的本地的類cpp或c,比如自定義了一個類HSprite.h HSprite.cpp
那麼需要添加到這個 LOCAL_SRC_FILES 中,如下:
../../Classes/AppDelegate.cpp \
../../Classes/HSprite.cpp
2. LOCAL_C_INCLUDES :編譯的本地類所在的路徑,例如你有一個HSprite類放在Himi的檔案夾中,那麼你可以如下形式添加:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
$(LOCAL_PATH)/../../Classes/Himi
那麼在你其他的類進行引用Himi檔案夾下的HSprite時,無需寫完整路徑,如下:
#include "Himi/HSprite.h"
可以直接如下導入:
#include "HSprite.h"
3. LOCAL_STATIC_LIBRARIES : 添加所需要連結的靜态庫
本章需要關注的是如下的配置:
4. call import-module : 編譯對應的子產品!
$(call import-module,cocos2dx) :具體是從 NDK_MODULE_PATH 路徑下的cocos2dx檔案夾下的Android.mk
那麼 NDK_MODULE_PATH 是指向哪裡呢?哪裡設定呢?下面詳細講解!
第二部分:
編譯過項目到Android的童鞋們肯定也知道build_native.sh 這個檔案,NDK_MODULE_PATH的路徑也在此檔案中進行設定, 如下圖:
如下:
APPNAME="Tuc4Android"
# options
buildexternalsfromsource=
usage(){
cat << EOF
usage: $0 [options]
Build C/C++ code for $APPNAME using Android NDK
OPTIONS:
-s Build externals from source
-h this help
EOF
}
while getopts "sh" OPTION; do
case "$OPTION" in
s)
buildexternalsfromsource=1
;;
h)
usage
exit 0
esac
done
# paths
if [ -z "${NDK_ROOT+aaa}" ];then
echo "please define NDK_ROOT"
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# ... use paths relative to current directory
COCOS2DX_ROOT="/Users/slater/Documents/cocos2d-2.1rc0-x-2.1.2-hotfix"
APP_ROOT="/Users/slater/Desktop/TestUserCpp/TestUserCpp"
APP_ANDROID_ROOT="/Users/slater/Desktop/TestUserCpp/TestUserCpp/proj.android"
echo "NDK_ROOT = $NDK_ROOT"
echo "COCOS2DX_ROOT = $COCOS2DX_ROOT"
echo "APP_ROOT = $APP_ROOT"
echo "APP_ANDROID_ROOT = $APP_ANDROID_ROOT"
# make sure assets is exist
if [ -d "$APP_ANDROID_ROOT"/assets ]; then
rm -rf "$APP_ANDROID_ROOT"/assets
mkdir "$APP_ANDROID_ROOT"/assets
# copy resources
for file in "$APP_ROOT"/Resources/*
do
if [ -d "$file" ]; then
cp -rf "$file" "$APP_ANDROID_ROOT"/assets
if [ -f "$file" ]; then
cp "$file" "$APP_ANDROID_ROOT"/assets
# copy icons (if they exist)
file="$APP_ANDROID_ROOT"/assets/Icon-72.png
cp "$file" "$APP_ANDROID_ROOT"/res/drawable-hdpi/icon.png
file="$APP_ANDROID_ROOT"/assets/Icon-48.png
cp "$file" "$APP_ANDROID_ROOT"/res/drawable-mdpi/icon.png
file="$APP_ANDROID_ROOT"/assets/Icon-32.png
cp "$file" "$APP_ANDROID_ROOT"/res/drawable-ldpi/icon.png
if [[ "$buildexternalsfromsource" ]]; then
echo "Building external dependencies from source"
"$NDK_ROOT"/ndk-build -C "$APP_ANDROID_ROOT" $* \
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/source"
else
echo "Using prebuilt externals"
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt"
在之前我們整合項目編譯到Android時其中我們需要關注的是 COCOS2DX_ROOT、 APP_ROOT、 APP_ANDROID_ROOT這三個路徑的設定。
那麼本次我們關注的是最下方 NDK_MODULE_PATH 是用于配置搜尋編譯子產品的基礎路徑! 此路徑與第一部分的Android.mk中 call import-module 相關!
${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt”
表示兩個路徑,一個是COCOS2DX_ROOT的路徑,另外一個是COCOS2DX_ROOT路徑下的/cocos2dx/platform/third_party/android/prebuilt
通過如上兩個知識點的簡單的介紹,大家可能會對編譯過程更深一步的了解。
現在開始講解本章重點: 解決自定義cpp類通過tolua++ binding LuaCocos2d後編譯到Android運作黑屏(沒有調用自定義cpp類)的問題!
當正确binding到LuaCocos2d後,我們iphone模拟器運作後一切正常,那麼當編譯到Android後,總是出現黑屏,并螢幕顯示有0個精靈 !
錯誤出在哪裡呢?!首先我們最容易想到的是檢檢視 Android項目下jni下的Android.mk中的LOCAL_SRC_FILES 是否包含了你自定義的類!确定是否參與編譯了!
如果确定參與編譯了,并Android項目能正常運作,但是還是運作黑屏的話,那麼你可以列印lua中調用的自定義類!最後會發現列印語句編譯到Android後,根本沒列印!基本上那就可以判定是LuaCocos2d這個類中并沒有binding你自定義類!
有些童鞋就奇怪說可以确定xcode項目下的LuaCocos2d類中确實binding了自定義類啊!!
是的,但是你看到的隻是ios項目所用的LuaCocos2d, 真正編譯到Android後的LuaCocos2d根本不是ios項目下的LuaCocos2d這個類!!
那麼到底是哪裡的LuaCocos2d被編譯到Android了呢?其實不難發現,通過Android.mk中看到編譯lua子產品的語句:
$(call import-module,scripting/lua/proj.android/jni) : 我們可以知道它指向cocos2dx引擎下的scripting/lua/proj.android/jni/Android.mk
路徑如下:
<a href="http://www.himigame.com/wp-content/uploads/2013/04/QQ20130427-1.png"></a>
打開後内容如下:
LOCAL_MODULE := cocos_lua_static
LOCAL_MODULE_FILENAME := liblua
LOCAL_SRC_FILES :=../../lua/lapi.c \
../../lua/lauxlib.c \
../../lua/lbaselib.c \
../../lua/lcode.c \
../../lua/ldblib.c \
../../lua/ldebug.c \
../../lua/ldo.c \
../../lua/ldump.c \
../../lua/lfunc.c \
../../lua/lgc.c \
../../lua/linit.c \
../../lua/liolib.c \
../../lua/llex.c \
../../lua/lmathlib.c \
../../lua/lmem.c \
../../lua/loadlib.c \
../../lua/lobject.c \
../../lua/lopcodes.c \
../../lua/loslib.c \
../../lua/lparser.c \
../../lua/lstate.c \
../../lua/lstring.c \
../../lua/lstrlib.c \
../../lua/ltable.c \
../../lua/ltablib.c \
../../lua/ltm.c \
../../lua/lua.c \
../../lua/lundump.c \
../../lua/lvm.c \
../../lua/lzio.c \
../../lua/print.c \
../../tolua/tolua_event.c \
../../tolua/tolua_is.c \
../../tolua/tolua_map.c \
../../tolua/tolua_push.c \
../../tolua/tolua_to.c \
../../cocos2dx_support/CCLuaBridge.cpp \
../../cocos2dx_support/CCLuaEngine.cpp \
../../cocos2dx_support/CCLuaStack.cpp \
../../cocos2dx_support/CCLuaValue.cpp \
../../cocos2dx_support/Cocos2dxLuaLoader.cpp \
../../cocos2dx_support/LuaCocos2d.cpp \
../../cocos2dx_support/tolua_fix.c
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../lua \
$(LOCAL_PATH)/../../tolua \
$(LOCAL_PATH)/../../cocos2dx_support
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ \
$(LOCAL_PATH)/../../lua \
$(LOCAL_PATH)/../../tolua \
$(LOCAL_PATH)/../../../../cocos2dx \
$(LOCAL_PATH)/../../../../cocos2dx/include \
$(LOCAL_PATH)/../../../../cocos2dx/platform \
$(LOCAL_PATH)/../../../../cocos2dx/platform/android \
$(LOCAL_PATH)/../../../../cocos2dx/kazmath/include \
$(LOCAL_PATH)/../../../../CocosDenshion/include
LOCAL_CFLAGS += -Wno-psabi
LOCAL_EXPORT_CFLAGS += -Wno-psabi
include $(BUILD_STATIC_LIBRARY)
從這個mk檔案的内容中我們可以看到參與編譯的LuaCocos2d類是相對于目前Android.mk 路徑的 ../../cocos2dx_support/LuaCocos2d.cpp \
從上面的附上的圖可以清楚的看到這個路徑,是目前Android.mk的路徑的上兩層後的目錄下的cocos2dx_support的LuaCocos2d.cpp檔案!
可能講到這裡,很多童鞋應該恍然大悟了吧!
雖然我們自定義類通過tolua++ binding到項目下的LuaCococs2d 中,但是參與Android編譯的LuaCocos2d并不是你項目下的!
OK,那下面給出幾種解決方式:
第一種:将我們項目下的已經binding好的LuaCococs2d類替換參與編譯的LuaCococs2d類!
(注:LuaCococs2d.h中導入的自定義類路徑,引用你項目下的對應類即可)
第二種: 将編譯的Lua子產品的Android.mk中的參與編譯的LuaCococs2d路徑改成自己項目下的LuaCococs2d路徑即可。
第三種: 通過修改 NDK_MODULE_PATH 路徑,将其指向我們項目下的libs路徑,然後将參與編譯的缺少子產品copy到我們的項目下對應路徑即可!
這個問題其實比較容易解決,但是主要的是了解原理!否則會越忙越亂!
本文轉自 xiaominghimi 51CTO部落格,原文連結:http://blog.51cto.com/xiaominghimi/1188481,如需轉載請自行聯系原作者