唉,首先说点闲话 – -。himi搞了不短的时间,这个问题一直没有解决,最后终于在张大(cocos2dx引擎开发者之一 张小明)的指导下解决了此问题。
在进入正文之前,讲解下一些基础知识:(当前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 中,如下:
../../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的路径也在此文件中进行设置, 如下图:
如下:
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 << 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
路径如下:
打开后内容如下:
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到我们的项目下对应路径即可!
这个问题其实比较容易解决,但是主要的是理解原理!否则会越忙越乱!