天天看點

【COCOS2DX-LUA 腳本開發之十四】解決自定義CPP類編譯到ANDROID運作黑屏的問題!

唉,首先說點閑話 – -。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,如需轉載請自行聯系原作者

繼續閱讀