我已经在这方面挣扎了很长一段时间,而且我已经结束了。基本上我是在我们的Android应用程序中包含一个包含本机组件的库。
在其中一个本机类的init方法中,init包含以下内容:
jclass clazz = env->FindClass(kClassPathName);
if (clazz == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
return;
}
GetFieldID调用始终抛出以下错误:
java.lang.NoSuchFieldError: no "I" field "mNativeContext" in class "Lcom/test/NativeLibrary;" or its superclasses
后面是长堆栈跟踪(省略因为它没用)。 它报告的类是该类的正确完全限定名称。
我已确认该课程中确实存在private int mNativeContext
。
我尝试的事情:
非常感谢任何帮助。
答案 0 :(得分:1)
看起来问题一直是Proguard。我第一次尝试保持符号时,我一定做错了。如果您遇到此问题,请尝试在proguard.cfg中添加类似的内容:
# Don't rename any Java class members that are accessed by name from native code!
-keep class com.test.NativeLibrary {
*** mNativeContext;
}
答案 1 :(得分:0)
我认为你的kClassPath错了。我没有使用硬编码路径,而且 而是从jCaller参数中拉出类,我将其用作 我所有原生函数的第一个参数。
这是我使用的代码片段,它将整数值写回 Java类。首先是Java类:
import java.nio.ByteBuffer;
public class Mp3 {
public int mDecodeSampleRate= 8000;
public int mDecodeChnlCt= 1;
public int mDecodeByteCt;
//Interface to Mp3 native library.
private native int nDecodeBlock(Mp3 mp3, int hDecoder, ByteBuffer src, int srcOffset, int srcCt, ByteBuffer dst);
public int decodeBuf(ByteBuffer src, int srcOffset, ByteBuffer dst) {
int consumeCt= 0;
consumeCt = nDecodeBlock(this, mDecoder, src, srcOffset, src.capacity(), dst);
//SampleRate, ChnlCt, and ByteCt will have been updated.
return(consumeCt);
}
public int decodeGetSampleRate() { return (mDecodeSampleRate); }
public int decodeGetChannelCt() { return (mDecodeChnlCt); }
public int decodeGetAudioByteCt() { return (mDecodeByteCt); }
}
现在是JNI C代码:
static void SetObjInt(JNIEnv *env, jobject obj, char *Name, int Val) {
jclass objClass;
jfieldID fieldID;
if(!(objClass= (*env)->GetObjectClass(env,obj))) {
LOGE("Unable to obtain objClass(%s)!",Name);
} else if(!(fieldID= (*env)->GetFieldID(env,objClass,Name,"I"))) {
LOGE("Unable to obtain field ID(%s).",Name);
} else {
//LOGD("Setting %s",Name);
(*env)->SetIntField(env,obj,fieldID,(jint)Val);
}
}
JNIEXPORT jint JNICALL Java_com_acme_mp3_nDecodeBlock(
JNIEnv *env, jobject obj, jobject jCaller,
jint jDecoder,
jobject jSrc, jint SrcOffset, jint SrcByteCt,
jobject jDst
) {
void *hDecoder= (void*)jDecoder;
unsigned char *pSrc= (*env)->GetDirectBufferAddress(env,jSrc);
short *pDst= (*env)->GetDirectBufferAddress(env,jDst);
int ConsumedCt= 0;
int DstCt= 0;
mp3_info_t Info;
ConsumedCt= mp3_decode(hDecoder,(void*)&pSrc[SrcOffset],SrcByteCt-SrcOffset,(short*)pDst,&Info);
if(ConsumedCt>0) {
SetObjInt(env,jCaller,"mDecodeSampleRate",Info.sample_rate);
SetObjInt(env,jCaller,"mDecodeChnlCt",Info.channels);
SetObjInt(env,jCaller,"mDecodeByteCt",Info.audio_bytes);
}
return(ConsumedCt);
}