2013-12-20 27 views
6

我想調用下面的Java方法中的Android調用靜態JNI方法返回來自C++

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(),但不能這樣做。任何想法我做錯了什麼?

+3

去過,因爲我用JNI,但我相當肯定,你不能傳遞c_str的'結果很長一段時間() '到一個Java方法,而是需要創建一個'jstring'來傳入。 –

+0

是的。用'NewStringUTF'或'NewString'從MUTF-8或UTF-16創建字符串。 – fadden

+0

謝謝@JoachimIsaksson。有效。如果你想把它作爲答案,我會很樂意標記爲正確的,並讚揚它。 – asloob

回答

2

您不能直接將一個結束字符串(從c_str()返回)作爲參數傳遞給Java/JNI方法。

要將它傳遞給該方法,請從nul終止的字符串創建一個jstring(例如,使用NewStringUTF)並傳遞該方法。

4

你很幸運,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(); 
} 

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