Llame a un método JNI estático para devolver una cadena de C ++

Estoy tratando de llamar al siguiente método java en Android

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

Desde c + + utilizando el siguiente código 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"); 

La aplicación se bloquea al realizar CallStaticMethodObject() . He comprobado que la firma del método es correcta usando javap . Y el LOGD("calling getLevelFile"); Se imprime bien y luego se bloquea. Puedo hacer otro CallStaticVoidMethod() s de la misma clase pero no éste. Alguna idea de lo que estoy haciendo mal?

No puede pasar directamente una cadena terminada por nul (devuelta desde c_str() ) como un parámetro a un método Java / JNI.

Para pasarlo al método, cree una jstring partir de la cadena terminada por nul (por ejemplo usando NewStringUTF ) y pase eso en su lugar.

Tienes suerte, Java y Android utilizan el conjunto de caracteres Unicode. Sin embargo, Android (por defecto) utiliza la codificación UTF-8, que JNI no admite intrínsecamente. Sin embargo, las clases Java son completamente capaces de convertir entre codificaciones de conjuntos de caracteres. Los constructores lang.java.String permiten especificar un conjunto de caracteres / codificación o usar el OS-default, que en Android, por supuesto, está codificado como UTF-8.

Para que sea más fácil (prefiero la codificación en Java, minimizando el código que llama a la biblioteca JNI), crear una sobrecarga de su método y hacer algunas de la implementación en Java:

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

Ahora el código JNI solo tiene que tratar con jbytearray, tanto para el parámetro como para el valor de retorno:

 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; 
  • Copiar un buffer de bytes con JNI
  • Cómo capturar excepciones generadas con código nativo que se ejecuta en Android
  • Uso de minizip con android ndk
  • Android Camera takePicture utiliza Previews small buffer
  • JNIEXPORT y JNICALL en Android NDK
  • Cómo construir una biblioteca compartida y llamarla en otro programa ndk
  • no se puede encontrar el símbolo "__android_log_write" - Registro nativo de Android
  • Extraño: no se puede cambiar el valor de Integer en jni
  • Mantener los métodos Java llamados desde Android JNI
  • Vinculación de bibliotecas de terceros (libs.a) con NDK
  • Llamar a un método java desde c ++ en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.