使用 JNI 将 4 字节 wchar_t 转换为字符串

4-byte wchar_t to String conversion using JNI

所以我有这个 CanvasView,它显示我的应用程序的调试信息。它基本上是透明背景的叠加视图,因此 canvas 中绘制的所有内容都在屏幕中浮动。由于我需要来自 returns wchar_t* 的本机 c++ 的一些信息,我如何使用 env->NewString 因为 android 现在使 wchar_t 是 4 个字节,而 jchar 是2 个字节?

我的 java 在我的库中调用本机 c++ 函数的代码:

private static String get_Name();
private class CanvasView extends View{
    public CanvasView(Context context){
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paintText = new Paint();
        paintText.setStyle(Paint.Style.FILL);
        paintText.setColor(Color.WHITE);
        paintText.setShadowLayer(5.5f, 0, 0, Color.BLACK);
        paintText.setTextSize(convertSizeToDp(7.5f));
        paintText.setTextAlign(Paint.Align.LEFT);

        paintText.drawText(get_Name(), x, y, paintText);


        // the rest of the code
        // ...
    }
}

get_Name 基本上 return 来自 NewString((const jchar* )myWchar, myLen)

的 jstring

return 结果有时是非 unicode 字符串,甚至我的应用程序在调用 NewString 时崩溃。

wchar_t 是 2 个字节的唯一平台是 Windows。在其他平台上,wchar_t 是 4 个字节。 env->NewString() 将 UTF-16 数据作为输入,因此您必须在调用 env->NewString() 之前将 wchar_t 数据从 UTF-32 转换为 UTF-16。否则,您将不得不使用 JNI 调用 Java String 构造函数,该构造函数采用 byte[] 数组和字符集作为输入,因此您可以直接从 UTF-32 数据创建字符串。

首先,使用JNI分配一个ByteBuffer

wchar_t *input = ...;
jobject bb = env->NewDirectByteBuffer((void *) input, wcslen(input) * sizeof(wchar_t));

接下来,调用Charset.forName("UTF-32LE").decode(bb).toString():(每段为一步)

jclass cls_Charset = env->FindClass("java/nio/charset/Charset");
jmethodID mid_Charset_forName = env->GetStaticMethodID(cls_Charset, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jobject charset = env->CallStaticObjectMethod(cls_Charset, mid_Charset_forName, env->NewStringUTF("UTF-32LE"));

jmethodID mid_Charset_decode = env->GetMethodID(cls_Charset, "decode", "(Ljava/nio/ByteBuffer;)Ljava/nio/CharBuffer;");
jobject cb = env->CallObjectMethod(charset, mid_Charset_decode, bb);

jclass cls_CharBuffer = env->FindClass("java/nio/CharBuffer");
jmethodID mid_CharBuffer_toString = env->GetMethodID(cls_CharBuffer, "toString", "()Ljava/lang/String;");
jstring ret = env->CallObjectMethod(cb, mid_CharBuffer_toString);

return ret;

注意:这取决于您所在平台的字节顺序。从 this answer 看来所有 Android 平台都是小端。如果您使用的是大端平台,则可能需要使用 UTF-32BE