【www.bbyears.com--php框架模板】
平台和版本
框架: cocos2d-x 3.4 final
设备: Nexus 4/5/7 with Android 5.0.1/5.0.2
NDK version: r9d
问题描述
一个 dragonbonesCPP 骨骼动画,在 iOS、Windows、Mac OS X、Android with 4.x 上表现完全正常,但在 Android 5.x 下表现不正常。
具体表现为解析骨骼动画数据的时候,既不 crash,也没有任何报错信息,整个程序就停住了。
问题追溯
通过加入 log 信息,发现问题处在 XMLDataParser::parserDragonBonesData 方法中,如下所示:
DragonBonesData* XMLDataParser::parseDragonBonesData(const void *rawDragonBonesData, float scale) const
{
CCLOG("Start parse dragonbones data.");
_armatureScale = scale;
const XMLElement *dragonBonesXML = static_cast
std::string version = dragonBonesXML->Attribute(ConstValues::A_VERSION.c_str());
CCLOG("Start parse A_VERSION.");
// TODO
/*
switch(version)
{
}
*/
CCLOG("A_FRAME_RATE: %s .", ConstValues::A_FRAME_RATE.c_str());
//打印了上面一行log 之后,整个程序就停住了
_frameRate = dragonBonesXML->IntAttribute(ConstValues::A_FRAME_RATE.c_str());
CCLOG("Start parse A_FRAME_RATE %d.", _frameRate);
DragonBonesData *dragonBonesData = new DragonBonesData();
//................
IntAttribute 是 tinyxml2 提供的解析方法,继续追溯,发现程序在 tinyxml2 中的 XMLUtil::ToInt 方法中停住。
bool XMLUtil::ToInt(const char *str, int *value)
{
CCLOG("XMLUtil::ToInt str: %s, value: %d", str, *value);
//打印了上面一行 log 之后,整个程序就停住了
if (DBTIXML_SSCANF(str, "%d", value) == 1)
{
CCLOG("XMLUtil::ToInt SSCANF true");
return true;
}
CCLOG("XMLUtil::ToInt SSCANF false");
return false;
}
//.............
而 DBTIXML_SSCANF 是一个宏,在 NDK 中被指向 sscanf 。
我本以为是 tinyxml2 的问题,但换了 github 最新版本的 tinyxml2 依然有同样问题,于是开始怀疑 NDK。
Google 一番之后,找到了一个关键的 issue 77988 。这里说到的情况和我碰到的几乎一模一样,看来这是 NDK 的 BUG 没错了:
Steps to recreate the problem:
– Make any call to sscanf, for example:
int v1 = 0;
sscanf(“1″, “%d”, &v1);
Notice that the application will not return from the call to sscanf and completely freeze without any error message generated
解决方案
方案1
升级 NDK 到 r10d ,该版本已经解决了这个问题:
Documented a fix to a libc++ sscanf/vsscanf hang that occurred in API level 21. The fix itself had been implemented in r10c. (Issue 77988)
但进行 NDK 连接的时候,我碰到了这样的报错信息:
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: error: /Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/libgcc.a(pr-support.o): multiple definition of ‘_Unwind_GetRegionStart’
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: /Volumes/HD1/Android/android-ndk-r10d/sources/cxx-stl/llvm-libc++/libs/armeabi/thumb/libc++_static.a(Unwind-EHABI.o): previous definition here
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: error: /Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/libgcc.a(pr-support.o): multiple definition of ‘_Unwind_GetLanguageSpecificData’
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: /Volumes/HD1/Android/android-ndk-r10d/sources/cxx-stl/llvm-libc++/libs/armeabi/thumb/libc++_static.a(Unwind-EHABI.o): previous definition here
collect2: error: ld returned 1 exit status
make: *** [obj/local/armeabi/libcocos2dlua.so] Error 1
我没有去解决这个问题,因为还有下一个方案。
方案2
如果担心 cocos2d-x 3.4 和 NDK r10d 的兼容性,也可以修改 Android 的编译参数:
编辑 android 项目中的 Application.mk 文件:
vim frameworks/runtime-src/proj.android/jni/Application.mk
将第一行:
APP_STL := c++_static
改为:
APP_STL := gnustl_static