[APP]從JNI傳送字串資料送到Java層遭遇\0問題


一般會認為,直接將字串資料直接呼叫到JNI的NewStringUTF, jstring的array中即可, 就像是下面這樣
char* p_str = ""; //你的字串資料
int len = ; //你的字串資料長度
jstring jstr = m_jenv->NewStringUTF(p_str);
return jstr;

但是如果你的字串是中有包含'\0'字元時,就無法這麼做,例如:"abc\0cde\0",因為NewStringUTF是以\0作為結束符號,你得字串長度就會不正確。

所以要傳上述字串回到java層,就需要一套轉換方法,比較簡單的方式是使用jbyte陣列來傳遞,像是下面這樣。
jbyteArray jbarray = m_jenv->NewByteArray(len);
m_jenv->SetByteArrayRegion(jbarray, 0, len, (const jbyte*)p_str);
return jbarray;

JNI回呼的Java方法大概會長這樣
    public void OnCallbackTwoString (byte[] b) {
        String s;
        try {
            s = new String(b, "UTF-8"); // or Charset.defaultCharset()
            ....
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, "OnCallbackTwoString:", e);
        }
    }

在JNI回呼OnCallbackTwoString時使用"([B)Z"

實際上遭遇\0的字元的狀況很多,尤其你的資料是透過native來的從其他sever來的多國語語言文字,都會遭遇這個問題。


另外,如果你是從Java送到JNI層, 建議是用GetStringUTFChars將java的unicode轉換成utf-8, Java官方有描述該轉換必定產生\0結尾的字串。而相關文件顯示java的'\0'傳遞到JNI時會被轉換成'0xc080',所以如果你需要用C的函數parse, 要記得處理這個問題

jstring jstr; // 從Java層來的String
const char *p_utfstr = env->GetStringUTFChars(jstr, 0);
jsize sz = m_jenv->GetStringUTFLength(str);
char* p_str = new p_str[sz+1];
memcpy(p_str, p_utfstr, sz+1);
m_jenv->ReleaseStringUTFChars(jstr, p_utfstr);
return p_str;

留言