java - 调用静态 JNI 方法以从 C++ 返回字符串

标签 java android c++ android-ndk java-native-interface

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

public static String getLevelFile(String levelName) { /*body*/}

从 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");

应用程序在执行 CallStaticMethodObject() 时崩溃。我已经使用 javap 验证了方法签名是正确的。 LOGD("calling getLevelFile"); 打印正常,然后崩溃。我可以执行同一个类中的其他 CallStaticVoidMethod() 但这个不行。知道我做错了什么吗?

最佳答案

您很幸运,Java 和 Android 都使用 Unicode 字符集。但是,Android(默认情况下)使用 UTF-8 编码,而 JNI 本身并不支持这种编码。尽管如此,Java 类完全能够在字符集编码之间进行转换。 lang.java.String 构造函数允许您指定字符集/编码或使用操作系统默认值,当然,在 Android 上,它被编码为 UTF-8。

为了使它更容易(我更喜欢用 Java 编码,尽量减少调用 JNI 库的代码),创建你的方法的重载并用 Java 做一些实现:

private static byte[] getLevelFile(byte[] levelName) {
    return getLevelFile(new String(levelName)).getBytes();
}

现在 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;

关于java - 调用静态 JNI 方法以从 C++ 返回字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20708857/

相关文章:

java - Libgdx 正交相机初始位置

android - 将动画添加到 android-wheel

android - OpenCV undefined reference `cv::fastFree(void*)'

java - LibGDX:序列不起作用

java - 延迟抛出的异常以添加软断言

android - 使用android :anyDensity

android - 无法捕获使用 android.provider.Telephony.SMS_RECEIVED 收到的短信

c++ - 条件默认构造函数可以在 GCC 中编译,但不能在 MSVC 中编译

c++ - 检查变量是否已被垃圾收集器声明

java - 本地主机网络监控和httpservlet请求