Call to C++ JNI NewStringUTF crashes android app when using many different kinds of emoji and languages (beyond ascii, but still valid modified utf-8)

孤者浪人 提交于 2019-12-04 18:57:39

We found a solution by sending the contents of the std::string in jbyte array and let the java side be java and return the jstring we could use on the C++ jni side. For us these strings are coming from the users keyboard and I have 170k crashes in one week that says they use emoji in character names and chat like crazy... and naming their avatars in itself caused crashes too. So any lobby a Android 5.x user joined would cause them to crash as soon as their client tried to render the other players names with the characters in question. In Android 4.x this was not an issue in that it just printed some garbage characters.

In your c++ side you can do something like this to achieve this function:

jstring JniHelper::getjString(const char *input) {
    JniMethodInfo minfo; // JniHelper

    bool hasMethod = JniHelper::getStaticMethodInfo (minfo, APPTAG_JNI_PACKAGE_NAME, "convertCStringToJniSafeString", "([B)Ljava/lang/String;");
    if (!hasMethod)
    {
        return minfo.env->NewStringUTF(""); // TODO Tune your response to fit your needs...
    }
    else
    {
        string nativeString = std::string(input); // has a bit of a code smell, there is probably a better way.
        // cite: http://stackoverflow.com/questions/27303316/c-stdstring-to-jstring-with-a-fixed-length
        jbyteArray array = minfo.env->NewByteArray(nativeString.length());
        minfo.env->SetByteArrayRegion(array,0,nativeString.length(),(jbyte*)nativeString.c_str());

        // cite: http://discuss.cocos2d-x.org/t/jni-return-string/9982/3
        jstring str = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, array);
        minfo.env->DeleteLocalRef(array);
        return str;
    }
}

On the java side turn that into a java string and return it in the same method:

public static String convertCStringToJniSafeString(byte[] input) {
    try {
        String nativeString = new String(input, "UTF-8"); // please debate what the safest charset should be?
        return nativeString;
    } catch (UnsupportedEncodingException e) {
        // TODO Simplistic Error handling, tune to your needs.
        Log.e(APPTAG, "Couldn't convert the jbyteArray to jstring");
        return ""; //JSTRING_CONVERT_FAIL
    }
}

In our case we wanted a jstring (which is inputed as modified UTF8) to feed to the rendering side and store for retrieval later, returning an empty string was just a choice we made to clue us in conversion failed.

I hope this helps someone find a way... maybe even the right way...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!