调用静态JNI方法从C++返回String

asl*_*oob 6 c++ java java-native-interface android android-ndk

我试图在Android中调用以下java方法

public static String getLevelFile(String levelName) { /*body*/}
Run Code Online (Sandbox Code Playgroud)

从c ++使用以下jni代码

JniMethodInfoJavaApi methodInfo;

    if (! getStaticMethodInfo(methodInfo, "getLevelFile", "(Ljava/lang/String;)Ljava/lang/String;"))
        {
            return std::string("");
        }
    LOGD("calling getLevelFile");
    jstring returnString = (jstring) methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, levelName.c_str());
    LOGD("returned from getLevelFile");
    methodInfo.env->DeleteLocalRef(methodInfo.classID);

    const char *js = methodInfo.env->GetStringUTFChars(returnString, NULL);
    std::string cs(js);
    methodInfo.env->ReleaseStringUTFChars(returnString, js);
    LOGD("returning Level data");
Run Code Online (Sandbox Code Playgroud)

应用程序在执行此操作时崩溃CallStaticMethodObject().我通过使用验证了方法签名是正确的javap.而LOGD("calling getLevelFile");打印精细,然后它崩溃.我可以CallStaticVoidMethod()从同一个班级做其他的但不是这个.我有什么想法我做错了吗?

Tom*_*get 5

你很幸运,Java和Android都使用Unicode字符集.但是,Android(默认情况下)使用UTF-8编码,JNI并不支持这种编码.尽管如此,Java类完全能够在字符集编码之间进行转换.该lang.java.String构造允许用户指定一个字符集/编码或使用OS-默认设置,即在Android,当然,被编码为UTF-8.

为了更容易(我更喜欢用Java编码,最小化调用JNI库的代码),创建方法的重载并在Java中执行一些实现:

private static byte[] getLevelFile(byte[] levelName) {
    return getLevelFile(new String(levelName)).getBytes();
}
Run Code Online (Sandbox Code Playgroud)

现在JNI代码只需处理jbytearray,包括参数和返回值:

JniMethodInfoJavaApi methodInfo;

if (! getStaticMethodInfo(methodInfo, "getLevelFile", "([B)[B"))
{
    return std::string("");
}

LOGD("calling getLevelFile");

int nameLength = levelName.length();
jbyteArray nameBytes = methodInfo.env->NewByteArray(nameLength);
methodInfo.env->SetByteArrayRegion(nameBytes, 0, nameLength, reinterpret_cast<const jbyte*>(levelName.c_str()));

jbyteArray returnString = (jbyteArray) methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, nameBytes);
LOGD("returned from getLevelFile");
methodInfo.env->DeleteLocalRef(methodInfo.classID);
methodInfo.env->DeleteLocalRef(nameBytes);

int returnLength = methodInfo.env->GetArrayLength(returnString);
std::string data;
data.reserve(returnLength);
methodInfo.env->GetByteArrayRegion(returnString, 0, returnLength, reinterpret_cast<jbyte*>(&data[0]));
methodInfo.env->DeleteLocalRef(returnString);

LOGD("returning Level data");
return data;
Run Code Online (Sandbox Code Playgroud)


Joa*_*son 3

您不能直接将 nul 终止的字符串(从 返回c_str())作为参数传递给 Java/JNI 方法。

要将其传递给方法,请jstring从以 nul 结尾的字符串创建一个(例如使用NewStringUTF)并传递它。