用C++调用Java代码:异常 java.lang.NoSuchMethodError

3
我正在尝试从JNI C++函数调用一些Java代码,但是我遇到了一个异常:java.lang.NoSuchMethodError。
调用Java代码的C++代码是从另一个本地库调用的回调函数。当我使用这里描述的设置时,这段代码运行得非常好:
基本上,一个APK使用了JNI,并且该JNI正在调用在其他地方编译的本地库)。
但是,我想将所有代码编译到AOSP中,因此我将我的本地库、JNI和APK代码放在vendor/MyCode/MyApp中。它可以编译,从Java调用的本地方法正常工作,但现在从JNI调用的Java代码全部崩溃了。
这是我想从JNI调用的方法的Java代码:
package com.android.mycode.myapp;

import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener
{
    private native int powerOn();

    ...

public void ndefRead(int tech, int protocol, byte[] ndef)
{
    Log.d(tag, "ndefRead()");
    Message msg = mHandler.obtainMessage();
    msg.what = MSG_NDEF_READ_RECEIVED;
    msg.obj = ndef;
    msg.arg1 = tech;
    msg.arg2 = protocol;
    mHandler.sendMessage(msg);
}

...
}

这是我的JNI代码,其中我注册了Java数据:

JNIEXPORT jint JNICALL
Java_com_android_mycode_myapp_MainActivity_powerOn(JNIEnv * env, jobject obj)
{
    LOGD("calling powerOn()"); //Or ANDROID_LOG_INFO, ...

    env->GetJavaVM(&javaVM);
    jclass cls = env->GetObjectClass(obj);
    activityClass = (jclass) env->NewGlobalRef(cls);
    activityObj = env->NewGlobalRef(obj);
    ...
    return status;
}

回调函数的JNI代码,其中调用了Java代码:
void EventCallback(UINT8 event, tEVT_CBACK_DATA* eventData)
{
LOGD("EventCallback() - event: 0x%x", event);

switch (event)
{
    case NDEF_READ_EVT:
    {
        LOGD("EventCallback() - NDEF_READ_EVT - data length: 0x%x", eventData->ndefReadEvt.length);

        JNIEnv *env;
        javaVM->AttachCurrentThread(&env, NULL);

        jmethodID ndefReadID = env->GetMethodID(activityClass, "ndefRead", "(II[B)V");
        if (ndefReadID == 0)
        {
            LOGD("Function ndefRead() not found");
            return;
        }

        jbyteArray result = env->NewByteArray(eventData->ndefReadEvt.length);
        if (result != NULL)
        {
            env->SetByteArrayRegion(result, 0, eventData->ndefReadEvt.length, (jbyte *) eventData->ndefReadEvt.p_ndef);
        }

        env->CallVoidMethod(activityObj, ndefReadID, eventData->ndefReadEvt.tech, eventData->ndefReadEvt.protocol, result);
        javaVM->DetachCurrentThread();
    }
        break;
}

JNI的makefile如下所示:
LOCAL_MODULE    := libinterface
LOCAL_SRC_FILES := interface.cpp
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := libnfc-nci

执行此代码时,我得到以下异常/错误消息:

Pending exception java.lang.NoSuchMethodError thrown by 'unknown throw location'
java.lang.NoSuchMethodError: no non-static method "Lcom/android/mycode/myapp/MainActivity;.ndefRead(II[B)V"

我看了这个网站上报告的几个类似问题,但是没有找到与我的问题相似的。如果有人有想法,将不胜感激。

编辑以添加ndefRead()函数的代码和JNI的makefile。


你正在附加到的线程上,activityClass 是否可以在该线程上使用?我快速查看了JNI文档,但对我来说并不清楚。 - Richard Critten
我认为使用 activityClass = (jclass) env->NewGlobalRef(cls) 这段代码应该可以解决问题。就像我之前所说的,在将所有内容放入 AOPS(供应商文件夹)并编译之前,这段代码是正常工作的。 - Alex
是的,使用类引用应该没问题,因为它已经创建了一个全局引用。我看到一个潜在的问题 - 取决于 EventCallback 的调用来自哪里 - AttachCurrentThread 本质上是 NOP(无操作)如果线程已经附加到 VM,则在先前附加到 AttachCurrentThread 的线程上调用 DetachCurrentThread 可能会导致问题。 - Michael
这会不会引起除NoSuchMethod之外的其他异常呢?因为我之前就遇到了AttachCurrentThread的问题(当退出应用程序时,我没有调用detach代码),而且错误消息也不同。 - Alex
package com.android.mycode.myapp;Java_com_android_st_nfcnintendothread_MainActivity_powerOn - Selvin
显示剩余3条评论
1个回答

0

这些错误通常是由于 make 文件或文件命名不正确引起的。

我没有看到任何像在 Android MK 中定义的 static { System.loadLibrary("your-c-module"); } 这样的代码。

#android.mk

include $(CLEAR_VARS)

LOCAL_MODULE    := your-c-module
LOCAL_SRC_FILES := main.cpp
LOCAL_STATIC_LIBRARIES += fancy-library
LOCAL_LDLIBS +=  -llog -ldl

此外,我不知道你是否已经过滤掉了它,但如果Java_com_android_st_nfcnintendothread_MainActivity_powerOn是你的 C 函数,那么你的包名应该为:com.android.st.nfcnintendothread,函数名为:MainActivity.powerOn
我只是随便说说,希望你能在上面找到一些有用的东西。

1
是的,我尝试过并对命名进行了一些筛选,但好像忘记了一些。我的JNI函数名称与Java包名称相同。这是我的JNI makefile的样子: italic bold ` LOCAL_MODULE := libinterface LOCAL_SRC_FILES := interface.cpp LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := libnfc-nci" - Alex
1
我重新编辑了代码以反映当前的实现。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接