今天忽然接到客服那边的反馈说,有玩家反馈进游戏后不久就崩溃了,我先是怀疑网络问题,由于一链接聊天成功后就挂了。以后用logcat抓日志,发现挂在jni那里了html
JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xf0java
string: ''mysql
in call to NewStringUTFandroid
from void org.cocos2dx.lib.Cocos2dxRenderer.nativeRender()git
调用JNI的NewStringUTF方法就挂了,而后让后台把聊天日志所有拉出来,另存为html放到mac机上查看。发现一个特殊的表情,以下图所示:github
我先让后台的同事,把全部聊天信息清理干净,这时候设备从新登陆进去没有问题了。因此肯定问题就是这个NewStringUTF方法引发的(但部分设备上有问题,部分设备没问题。看了一下好像是Android5.0及之后的系统就有此问题),问了其它同事,发现他们以前遇到过而且处理了。sql
有二种方案:一种是升级NDK,另一种是C++传给Java时使用byte[],Java里再把byte[]转成String,避免NewStringUTF致使的崩溃。数据库
我用的是cocos2d-x 2.x版本,找到CCImage.cpp文件,修改getBitmapFromJava方法网络
bool getBitmapFromJava(const char *text, int nWidth, int nHeight, CCImage::ETextAlign eAlignMask, const char * pFontName, float fontSize)
{
JniMethodInfo methodInfo;
if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmap",
"([BLjava/lang/String;IIII)V"))
{
CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__);
return false;
}
/**create bitmap
* this method call Cococs2dx.createBitmap()(java code) to create the bitmap, the java code
* will call Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC() to init the width, height
* and data.
* use this appoach to decrease the jni call number
*/
int strLen = strlen(text);
jbyteArray byteArray = methodInfo.env->NewByteArray(strLen);
methodInfo.env->SetByteArrayRegion(byteArray, 0, strLen, reinterpret_cast<const jbyte*>(text));
// jstring jstrText = methodInfo.env->NewStringUTF(text);
jstring jstrFont = methodInfo.env->NewStringUTF(pFontName);
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, byteArray,
jstrFont, (int)fontSize, eAlignMask, nWidth, nHeight);
// methodInfo.env->DeleteLocalRef(jstrText);
methodInfo.env->DeleteLocalRef(byteArray);
methodInfo.env->DeleteLocalRef(jstrFont);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
return true;
}
注释部分为原来的代码,将string替换为byte[]再传给Java便可,其它地方若是也遇到JNI崩溃的问题,也按上面进行修改便可。app
符一个字符串与jbyteArray的互转函数
jbyteArray as_byte_array(unsigned char* buf, int len) {
jbyteArray array = env->NewByteArray(len);
env->SetByteArrayRegion(array, 0, len, reinterpret_cast<jbyte*>(buf));
return array;
}
unsigned char* as_unsigned_char_array(jbyteArray array) {
int len = env->GetArrayLength(array);
unsigned char* buf = new unsigned char[len];
env->GetByteArrayRegion(array, 0, len, reinterpret_cast<jbyte*>(buf));
return buf;
}
mysql 5.5以前仅支持3个字节,若是游戏中有留言等功能要存进数据库的记录,那么你就须要过滤这些字符了,否则就会插入数据报错。
更多阅读连接:
JNI UTF-8 encoding bug with some characters
Android ICS 4.0 NDK NewStringUTF is crashing down the App
A correct way to convert byte[] in java to unsigned char* in C++, and vice versa?
Android 上的 制表符(tab) —— 一个神奇的字符 (cocos2dx crash)
Android 上的 制表符(tab) —— 一个神奇的字符 (二)