唉,首先说点闲话 – -。Himi搞了不短的时间,这个问题一直没有解决,最后终于在张大(cocos2dx引擎开发者之一 张小明)的指导下解决了此问题。
本章基于上一篇 COCOS2DX-LUA脚本开发(十三) 解决Cocos2dx-Lua编译到Android出现一系列问题等 与之前的项目整合 【Cocos2d-X(2.x) 游戏开发系列之二】cocos2dx最新2.x版本跨平台整合NDK+Xcode,Xcode编写&编译代码,Android导入打包运行即可!)
在进入正文之前,讲解下一些基础知识:(当前Himi的版本是cocos2xx 2.1.2 hotfix)
第一部分:
编译过项目到Android的童鞋们肯定知道创建好的Android项目下的jni下的Android.mk 这个文件,如下:
01.
LOCAL_PATH := $(call my-dir)
02.
03.
include $(CLEAR_VARS)
04.
05.
LOCAL_MODULE := game_shared
06.
07.
LOCAL_MODULE_FILENAME := libgame
08.
09.
LOCAL_SRC_FILES := hellocpp/main.cpp \
10.
../../Classes/AppDelegate.cpp
11.
12.
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
13.
14.
LOCAL_STATIC_LIBRARIES := curl_static_prebuilt
15.
16.
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
17.
LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static
18.
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_lua_static
19.
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_extension_static
20.
21.
include $(BUILD_SHARED_LIBRARY)
22.
23.
$(call
import
-module,cocos2dx)
24.
$(call
import
-module,CocosDenshion/android)
25.
$(call
import
-module,scripting/lua/proj.android/jni)
26.
$(call
import
-module,cocos2dx/platform/third_party/android/prebuilt/libcurl)
27.
$(call
import
-module,extensions)
这个文件中,主要我们关注如下几个配置:‘
1. LOCAL_SRC_FILES : 编译到Android的本地的类cpp或c,比如自定义了一个类HSprite.h HSprite.cpp
那么需要添加到这个 LOCAL_SRC_FILES 中,如下:
1.
LOCAL_SRC_FILES := hellocpp/main.cpp \
2.
../../Classes/AppDelegate.cpp \
3.
../../Classes/HSprite.cpp
2. LOCAL_C_INCLUDES :编译的本地类所在的路径,例如你有一个HSprite类放在Himi的文件夹中,那么你可以如下形式添加:
1.
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
2.
$(LOCAL_PATH)/../../Classes/Himi
3.
4.
那么在你其他的类进行引用Himi文件夹下的HSprite时,无需写完整路径,如下:
5.
#include
"Himi/HSprite.h"
6.
7.
可以直接如下导入:
8.
#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的路径也在此文件中进行设置, 如下图:
如下:
01.
APPNAME=
"Tuc4Android"
02.
03.
# options
04.
05.
buildexternalsfromsource=
06.
07.
usage(){
08.
cat << EOF
09.
usage: $
0
[options]
10.
11.
Build C/C++ code
for
$APPNAME using Android NDK
12.
13.
OPTIONS:
14.
-s Build externals from source
15.
-h
this
help
16.
EOF
17.
}
18.
19.
while
getopts
"sh"
OPTION;
do
20.
case
"$OPTION"
in
21.
s)
22.
buildexternalsfromsource=
1
23.
;;
24.
h)
25.
usage
26.
exit
0
27.
;;
28.
esac
29.
done
30.
31.
# paths
32.
33.
if
[ -z
"${NDK_ROOT+aaa}"
];then
34.
echo
"please define NDK_ROOT"
35.
exit
1
36.
fi
37.
38.
DIR=
"$( cd "
$( dirname
"${BASH_SOURCE[0]}"
)
" && pwd )"
39.
# ... use paths relative to current directory
40.
COCOS2DX_ROOT=
"/Users/slater/Documents/cocos2d-2.1rc0-x-2.1.2-hotfix"
41.
APP_ROOT=
"/Users/slater/Desktop/TestUserCpp/TestUserCpp"
42.
APP_ANDROID_ROOT=
"/Users/slater/Desktop/TestUserCpp/TestUserCpp/proj.android"
43.
44.
echo
"NDK_ROOT = $NDK_ROOT"
45.
echo
"COCOS2DX_ROOT = $COCOS2DX_ROOT"
46.
echo
"APP_ROOT = $APP_ROOT"
47.
echo
"APP_ANDROID_ROOT = $APP_ANDROID_ROOT"
48.
49.
# make sure assets is exist
50.
if
[ -d
"$APP_ANDROID_ROOT"
/assets ]; then
51.
rm -rf
"$APP_ANDROID_ROOT"
/assets
52.
fi
53.
54.
mkdir
"$APP_ANDROID_ROOT"
/assets
55.
56.
# copy resources
57.
for
file in
"$APP_ROOT"
/Resources/*
58.
do
59.
if
[ -d
"$file"
]; then
60.
cp -rf
"$file"
"$APP_ANDROID_ROOT"
/assets
61.
fi
62.
63.
if
[ -f
"$file"
]; then
64.
cp
"$file"
"$APP_ANDROID_ROOT"
/assets
65.
fi
66.
done
67.
68.
# copy icons (
if
they exist)
69.
file=
"$APP_ANDROID_ROOT"
/assets/Icon-
72
.png
70.
if
[ -f
"$file"
]; then
71.
cp
"$file"
"$APP_ANDROID_ROOT"
/res/drawable-hdpi/icon.png
72.
fi
73.
file=
"$APP_ANDROID_ROOT"
/assets/Icon-
48
.png
74.
if
[ -f
"$file"
]; then
75.
cp
"$file"
"$APP_ANDROID_ROOT"
/res/drawable-mdpi/icon.png
76.
fi
77.
file=
"$APP_ANDROID_ROOT"
/assets/Icon-
32
.png
78.
if
[ -f
"$file"
]; then
79.
cp
"$file"
"$APP_ANDROID_ROOT"
/res/drawable-ldpi/icon.png
80.
fi
81.
82.
if
[[
"$buildexternalsfromsource"
]]; then
83.
echo
"Building external dependencies from source"
84.
"$NDK_ROOT"
/ndk-build -C
"$APP_ANDROID_ROOT"
$* \
85.
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/source"
86.
else
87.
echo
"Using prebuilt externals"
88.
"$NDK_ROOT"
/ndk-build -C
"$APP_ANDROID_ROOT"
$* \
89.
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt"
90.
fi
在之前我们整合项目编译到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中那么编译Android绝对是正确运行的,但是难免会自定义一些类供lua脚本使用,一般我们可以通过tolua++进行binding到LuaCocos2d中(参考Himi的另外一篇文章:COCOS2DX-LUA 脚本开发(四) 使用tolua++编译pkg 从而创建自定义类让Lua脚本使用)
当正确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
路径如下:
打开后内容如下:
01.
LOCAL_PATH := $(call my-dir)
02.
include $(CLEAR_VARS)
03.
04.
LOCAL_MODULE := cocos_lua_static
05.
06.
LOCAL_MODULE_FILENAME := liblua
07.
08.
LOCAL_SRC_FILES :=../../lua/lapi.c \
09.
../../lua/lauxlib.c \
10.
../../lua/lbaselib.c \
11.
../../lua/lcode.c \
12.
../../lua/ldblib.c \
13.
../../lua/ldebug.c \
14.
../../lua/ldo.c \
15.
../../lua/ldump.c \
16.
../../lua/lfunc.c \
17.
../../lua/lgc.c \
18.
../../lua/linit.c \
19.
../../lua/liolib.c \
20.
../../lua/llex.c \
21.
../../lua/lmathlib.c \
22.
../../lua/lmem.c \
23.
../../lua/loadlib.c \
24.
../../lua/lobject.c \
25.
../../lua/lopcodes.c \
26.
../../lua/loslib.c \
27.
../../lua/lparser.c \
28.
../../lua/lstate.c \
29.
../../lua/lstring.c \
30.
../../lua/lstrlib.c \
31.
../../lua/ltable.c \
32.
../../lua/ltablib.c \
33.
../../lua/ltm.c \
34.
../../lua/lua.c \
35.
../../lua/lundump.c \
36.
../../lua/lvm.c \
37.
../../lua/lzio.c \
38.
../../lua/print.c \
39.
../../tolua/tolua_event.c \
40.
../../tolua/tolua_is.c \
41.
../../tolua/tolua_map.c \
42.
../../tolua/tolua_push.c \
43.
../../tolua/tolua_to.c \
44.
../../cocos2dx_support/CCLuaBridge.cpp \
45.
../../cocos2dx_support/CCLuaEngine.cpp \
46.
../../cocos2dx_support/CCLuaStack.cpp \
47.
../../cocos2dx_support/CCLuaValue.cpp \
48.
../../cocos2dx_support/Cocos2dxLuaLoader.cpp \
49.
../../cocos2dx_support/LuaCocos2d.cpp \
50.
../../cocos2dx_support/tolua_fix.c
51.
52.
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../lua \
53.
$(LOCAL_PATH)/../../tolua \
54.
$(LOCAL_PATH)/../../cocos2dx_support
55.
56.
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ \
57.
$(LOCAL_PATH)/../../lua \
58.
$(LOCAL_PATH)/../../tolua \
59.
$(LOCAL_PATH)/../../../../cocos2dx \
60.
$(LOCAL_PATH)/../../../../cocos2dx/include \
61.
$(LOCAL_PATH)/../../../../cocos2dx/platform \
62.
$(LOCAL_PATH)/../../../../cocos2dx/platform/android \
63.
$(LOCAL_PATH)/../../../../cocos2dx/kazmath/include \
64.
$(LOCAL_PATH)/../../../../CocosDenshion/include
65.
66.
LOCAL_CFLAGS += -Wno-psabi
67.
LOCAL_EXPORT_CFLAGS += -Wno-psabi
68.
69.
include $(BUILD_STATIC_LIBRARY)
从这个mk文件的内容中我们可以看到参与编译的LuaCocos2d类是相对于当前Android.mk 路径的 ../../cocos2dx_support/LuaCocos2d.cpp \
从上面的附上的图可以清楚的看到这个路径,是当前Android.mk的路径的上两层后的目录下的cocos2dx_support的LuaCocos2d.cpp文件!
可能讲到这里,很多童鞋应该恍然大悟了吧! www.it165.net
虽然我们自定义类通过tolua++ binding到项目下的LuaCococs2d 中,但是参与Android编译的LuaCocos2d并不是你项目下的!
OK,那下面给出几种解决方式:
第一种:将我们项目下的已经binding好的LuaCococs2d类替换参与编译的LuaCococs2d类!
(注:LuaCococs2d.h中导入的自定义类路径,引用你项目下的对应类即可)
第二种: 将编译的Lua模块的Android.mk中的参与编译的LuaCococs2d路径改成自己项目下的LuaCococs2d路径即可。
第三种: 通过修改 NDK_MODULE_PATH 路径,将其指向我们项目下的libs路径,然后将参与编译的缺少模块copy到我们的项目下对应路径即可!
这个问题其实比较容易解决,但是主要的是理解原理!否则会越忙越乱!