emoji表情引起的JNI崩潰

今天忽然接到客服那邊的反饋說,有玩家反饋進遊戲後不久就崩潰了,我先是懷疑網絡問題,由於一鏈接聊天成功後就掛了。以後用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?

emoji處理方式大起底

cocos2d-x android遊戲使用本身的字體

Android 上的 製表符(tab) —— 一個神奇的字符 (cocos2dx crash)

Android 上的 製表符(tab) —— 一個神奇的字符 (二)

 

Java Native Interface

C and C++ JNI - University of Cambridge

Java Native Interface

探索在Android中使用Emoji Font的方法

相關文章
相關標籤/搜索