【问题标题】:Cannot encode to UTF-8 in JNI无法在 JNI 中编码为 UTF-8
【发布时间】:2016-06-25 17:14:07
【问题描述】:

我正在尝试返回用 UTF-8 编码的 jstring,但应用程序崩溃并且 JNI 写出错误:

JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0x30

我的sn-p:

jstring Java_tgio_rncryptor_RNCryptorNative_generateKey(JNIEnv *env, jobject instance, const jstring salt_, const jstring password_)
 {
    const char *salt = env->GetStringUTFChars(salt_, 0);
    const char *password = env->GetStringUTFChars(password_, 0);
    RNCryptor *cryptor = new RNCryptor();
    string value = (char * )cryptor->generateKey(salt, password).data();
    delete cryptor;
    env->ReleaseStringUTFChars(salt_, salt);
    env->ReleaseStringUTFChars(password_, password);
    return env->NewStringUTF(value.c_str());
}

也试过了:

const char *returning = env->GetStringUTFChars(env->NewStringUTF(value.c_str()), 0);
return env->NewStringUTF(returning);

有什么建议吗?

【问题讨论】:

    标签: java android encoding utf-8 java-native-interface


    【解决方案1】:

    cryptor->generateKey 返回SecByteBlock,一个字节序列。虽然转换为 (char *) 并构造 std::string 是有意义的,因为它们不仅仅处理文本,jstring 包含文本(来自 UTF-16 编码中的 Unicode 字符集)。

    您的代码尝试将非文本字节转换为 Java 字符串。如果你真的想这样做,你必须使用一个字符集和编码,任何值 0-255 的序列都是有效的。 (CP437 就是其中之一。)

    但是,您可以将数据保留在更接近其本质的数据类型中:返回 Java byte[]。然后在 Java 端,如果你想将密钥作为字符串传递,你可以将字节序列转换为Base 64

    一般来说,加密算法对字节序列或块进行操作。只有应用程序或包装函数处理文本。您将检查 RNCryptor 是否为您执行此操作,但在我看来并非如此。

    【讨论】:

      【解决方案2】:

      试试这个 UTF-8 编码

        try {
      URLEncoder.encode(yourValue, "UTF-8")
      
      } catch (UnsupportedEncodingException e) {
                  e.printStackTrace();
              }
      

      【讨论】:

      • 我也在 Java 源代码中试过这个,但没有结果。 :(
      【解决方案3】:

      并非所有字节都是有效的可打印字符,并且大多数不是有效的 unicode 字符。当需要将字节数组编码为字符串时,标准做法是使用 Base64 或十六进制。

      【讨论】:

        【解决方案4】:

        我通过返回 jcharArray 而不是 jstring 解决了这个问题:

             env->ReleaseStringUTFChars(salt_, salt);
             env->ReleaseStringUTFChars(password_, password);
             char array[1024];
             strcpy(array, value.c_str());
             jcharArray charArr = env->NewCharArray(1024);
             env->SetCharArrayRegion(charArr, 0, 1024, (jchar *) array);
             return charArr;
        

        我只是在Java源代码中做了String.valueOf(arr),并打印出来。

        【讨论】:

        • 在 Java 中,char 或 jchar 是 UTF-16 代码单元。您似乎将两个字节组合成一个 jchar。如果该 jchar 值不是有效的 UTF-16 代码单元,或者它是 surrogate 后面没有或前面没有相应的代理项,您可能会遇到麻烦。我认为你也过度阅读了你的array 100%。
        • 是的,它可以改进,但我认为它或多或少是正确的结构。如果您愿意,请告诉我您的建议。
        • 所以你建议使用 byte[] 而不是 char[] ?
        • github.com/TGIO/RNCryptorNative/commit/…我刚试过,你可以看看,告诉我你的意见
        • 本机实现看起来不错,但我对new String(arr, "UTF-16") 感到困惑。我不认为arr 代表文本。
        猜你喜欢
        • 2011-01-01
        • 2021-03-22
        • 2020-12-26
        • 1970-01-01
        • 2012-10-11
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        • 2015-04-28
        相关资源
        最近更新 更多