转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/lua-game/1388.html
唉,首先说点闲话 – -。Himi搞了不短的时间,这个问题一直没有解决,最后终于在张大(cocos2dx引擎开发者之一 张小明)的指导下解决了此问题。
本章基于上一篇 【COCOS2DX-LUA 脚本开发之十三】 与之前的项目整合 【Cocos2d-X(2.x) 游戏开发系列之二】cocos2dx最新2.x版本跨平台整合NDK+Xcode,Xcode编写&编译代码,Android导入打包运行即可!)
在进入正文之前,讲解下一些基础知识:(当前Himi的版本是cocos2xx 2.1.2 hotfix)
第一部分:
编译过项目到Android的童鞋们肯定知道创建好的Android项目下的jni下的Android.mk 这个文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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 中,如下:
1
2
3
|
LOCAL_SRC_FILES
:
=
hellocpp
/
main
.
cpp
\
.
.
/
.
.
/
Classes
/
AppDelegate
.
cpp
\
.
.
/
.
.
/
Classes
/
HSprite
.
cpp
|
2. LOCAL_C_INCLUDES :编译的本地类所在的路径,例如你有一个HSprite类放在Himi的文件夹中,那么你可以如下形式添加:
1
2
3
4
5
6
7
8
|
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的路径也在此文件中进行设置, 如下图:
如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
APPNAME
=
"Tuc4Android"
# options
buildexternalsfromsource
=
usage
(
)
{
cat
&
lt
;
&
lt
;
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
fi
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
fi
if
[
-
f
"$file"
]
;
then
cp
"$file"
"$APP_ANDROID_ROOT"
/
assets
fi
done
# copy icons (if they exist)
file
=
"$APP_ANDROID_ROOT"
/
assets
/
Icon
-
72.png
if
[
-
f
"$file"
]
;
then
cp
"$file"
"$APP_ANDROID_ROOT"
/
res
/
drawable
-
hdpi
/
icon
.
png
fi
file
=
"$APP_ANDROID_ROOT"
/
assets
/
Icon
-
48.png
if
[
-
f
"$file"
]
;
then
cp
"$file"
"$APP_ANDROID_ROOT"
/
res
/
drawable
-
mdpi
/
icon
.
png
fi
file
=
"$APP_ANDROID_ROOT"
/
assets
/
Icon
-
32.png
if
[
-
f
"$file"
]
;
then
cp
"$file"
"$APP_ANDROID_ROOT"
/
res
/
drawable
-
ldpi
/
icon
.
png
fi
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_ROOT"
/
ndk
-
build
-
C
"$APP_ANDROID_ROOT"
$
*
\
"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt"
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
路径如下:
打开后内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
LOCAL_PATH
:
=
$
(
call
my
-
dir
)
include
$
(
CLEAR_VARS
)
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到我们的项目下对应路径即可!
这个问题其实比较容易解决,但是主要的是理解原理!否则会越忙越乱!