Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android JNI GetMethodID()失败_Java_Android_C_Cordova_Java Native Interface - Fatal编程技术网

Java Android JNI GetMethodID()失败

Java Android JNI GetMethodID()失败,java,android,c,cordova,java-native-interface,Java,Android,C,Cordova,Java Native Interface,我正在尝试构建一个Cordova插件,以支持在Ionic Cordova应用程序中使用的C库。到目前为止,JavaScript→Java和Java→我的代码工作的C部分。我可以在手机上运行的Android Studio中成功调试C代码。但是,我的C库有一个回调方法,需要向上传递堆栈(C→JAVA→JavaScript),我在如何让JNI方法正常工作方面遇到了问题。以下是我目前的代码: AgentMgrService.Java package com.example; import ... p

我正在尝试构建一个Cordova插件,以支持在Ionic Cordova应用程序中使用的C库。到目前为止,JavaScript→Java和Java→我的代码工作的C部分。我可以在手机上运行的Android Studio中成功调试C代码。但是,我的C库有一个回调方法,需要向上传递堆栈(C→JAVA→JavaScript),我在如何让JNI方法正常工作方面遇到了问题。以下是我目前的代码:

AgentMgrService.Java

package com.example;

import ...

public class AgentMgrService {

    private static final String TAG = "AgentMgrService";
    private boolean libLoaded = false;
    private static Context mContext;

    public CallbackContext jsCallback;

    // C-function interface
    public static native void startAgentMgr(String agentMgrConfig);
    public static native void stopAgentMgr();

    // load library
    static {
        System.loadLibrary("lib_agentmgr");
    }
    public AgentMgrService(Context context) {
        mContext = context;
    }

    public void startMobileAgentMgr(String agentmgrConfig) throws RemoteException {
        startAgentMgr(agentmgrConfig);

    public void testMe() {
        Log.d(TAG, "testMe!");
    }

    public String toString() {
        Log.d(TAG, "This is a string!");
        return "This is a string!";
    }

}
AgentMgrJni.c

#include ...

static JavaVM* _jamgr_appVm = NULL;
static jobject _jamgr_appObj = NULL;

void
Java_com_example_AgentMgrService_startAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    if (_jamgr_appObj == NULL) {
      _jamgr_appObj = (*env)->NewGlobalRef(env, thiz);
    }

    //... Stuff happens here ...

    jni_callback();

}

int
jni_callback()
{
    JNIEnv* env = NULL;
    jint retval = 0;
    jmethodID mid = NULL;
    jclass cls = NULL;

    retval = (*_jamgr_appVm)->GetEnv(_jamgr_appVm, (void**) &env, JNI_VERSION_1_6);

    cls = (*env)->GetObjectClass(env, _jamgr_appObj);


    //Try the toString() method
    mid = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;");
    jobject strObj = (*env)->CallObjectMethod(env, _jamgr_appObj, mid);
    const char* str = (*env)->GetStringUTFChars(env, strObj, NULL);
    printf("\nCalling class is: %s\n", str);
    //this prints "class com.example.AgentMgrService"

    mid = (*env)->GetMethodID(env, cls, "testMe", "()V");
    //this returns NULL and thus the below call fails
    (*env)->CallVoidMethod(env, _jamgr_appObj, mid, jstr);

    return retval;
}
运行上述代码时,在第一个
GetMethodID()
出现之前,一切正常。调用
toString()
时,我得到了样板文件
“class com.example.AgentMgrService”
。但是等等,我重载了
toString()
!此外,尝试获取
testMe()
会返回NULL,因此无法找到该方法。所以我在正确的类中,实际上可以从C中调用一些Java方法,但不能调用我定义的方法?我还没有尝试过使任何东西静止,但我不确定这是否会有帮助

const char* str = (*env)->GetStringUTFChars(env, strObj, NULL);
printf("\nCalling class is: %s\n", str);
//this prints "class com.example.AgentMgrService"
它打印调用
\u jamgr\u appObj.toString()
的结果。这是
“这是一个字符串!”
。它肯定不是
“class com.example.AgentMgrService”
,它打印的任何内容肯定不是“调用类”。您正在这里查找
getClass().toString()

否则这不是真正的代码。这似乎更有可能

//this returns NULL
它返回零<代码>方法ID不是指针

// ... and thus the below call fails
(*env)->CallVoidMethod(env, _jamgr_appObj, mid, jstr);
为什么您不直接将原始的
thiz
对象和
JNIEnv*
传递到
jni\u callback()
,这对我来说是个谜。您当然不需要使用
GlobalRef
或调用
String.toString()


这段代码中缺少错误检查,令人遗憾。每个JNI调用之后都必须检查其结果,如果错误,则必须使用异常检查或打印或抛出方法之一。而不是像没有发生错误一样继续操作。

问题的答案在于本机方法是否是静态的

在JNI,如果你有

public static native void startAgentMgr(String agentMgrConfig);
public static native void stopAgentMgr();
在java方面,当调用此方法时,
this
对象将是一个类而不是实例。。毕竟,这个方法是静态的,它没有
这个

但是,如果将其更改为(注意缺少
static
关键字):

然后,当您运行代码时,
参数将是调用此方法的对象的实例

例如:

package com.example.brandon.test;

import android.content.Context;
import android.os.RemoteException;
import android.util.Log;

public class AgentMgrService {
    private static final String TAG = "AgentMgrService";

    // load library
    static {
        System.loadLibrary("lib_agentmgr");
    }

    // C-function interface
    public native void startAgentMgr(String agentMgrConfig);
    public native void stopAgentMgr();

    public AgentMgrService(Context context) {

    }

    public void startMobileAgentMgr(String agentmgrConfig) throws RemoteException {
        startAgentMgr(agentmgrConfig);
    }

    public void testMe() {
        Log.d(TAG, "testMe!");
    }

    @Override
    public String toString() {
        Log.d(TAG, "This is a string!");
        return "This is a string!";
    }
}
本机代码:

#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

static JavaVM* _jamgr_appVm = NULL;
static jobject _jamgr_appObj = NULL;

int jni_callback();

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* aReserved)
{
    _jamgr_appVm = vm;
    return JNI_VERSION_1_4;
}

JNIEXPORT void JNICALL
Java_com_example_brandon_test_AgentMgrService_startAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    if (_jamgr_appVm == NULL)
    {
        (*env)->GetJavaVM(env, *_jamgr_appVm);
    }

    if (_jamgr_appObj == NULL) {
        _jamgr_appObj = (*env)->NewGlobalRef(env, thiz);
    }

    jni_callback();

}

JNIEXPORT void JNICALL
Java_com_example_brandon_test_AgentMgrService_stopAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    (*env)->DeleteGlobalRef(env, _jamgr_appObj);
    _jamgr_appObj = NULL;
}

int jni_callback()
{
    JNIEnv* env = NULL;
    jint retval = (*_jamgr_appVm)->GetEnv(_jamgr_appVm, (void**) &env, JNI_VERSION_1_4);

    if (retval == JNI_OK)
    {
        jclass cls = (*env)->GetObjectClass(env, _jamgr_appObj);
        if (cls)
        {
            jmethodID  mid = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;");
            if (mid)
            {
                jobject strObj = (*env)->CallObjectMethod(env, _jamgr_appObj, mid);

                if (strObj)
                {
                    const char *str = (*env)->GetStringUTFChars(env, strObj, NULL);
                    printf("\nCalling class is: %s\n", str);
                    (*env)->ReleaseStringUTFChars(env, strObj, str);
                    strObj = NULL;
                }


                mid = (*env)->GetMethodID(env, cls, "testMe", "()V");

                if (mid)
                {
                    (*env)->CallVoidMethod(env, _jamgr_appObj, mid);
                }
            }
        }

    }

    return retval;
}
#包括
#包括
#包括
#包括
静态JavaVM*\u jamgr\u appVm=NULL;
静态作业对象_jamgr_appObj=NULL;
int jni_回调();
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM*vm,void*aReserved)
{
_jamgr_appVm=vm;
返回JNI_版本_1_4;
}
JNIEXPORT void JNICALL
Java\u com\u示例\u brandon\u测试\u代理GRService\u startAgentMgr(
JNIEnv*env,
jobject thiz,
jstring配置(数据)
{
if(_jamgr_appVm==NULL)
{
(*env)->GetJavaVM(env,*\u jamgr\u appVm);
}
如果(_jamgr_appObj==NULL){
_jamgr_appObj=(*env)->NewGlobalRef(env,thiz);
}
jni_回调();
}
JNIEXPORT void JNICALL
Java\u com\u示例\u brandon\u test\u AgentMgrService\u stopAgentMgr(
JNIEnv*env,
jobject thiz,
jstring配置(数据)
{
(*env)->DeleteGlobalRef(env,_jamgr_appbj);
_jamgr_appObj=NULL;
}
int jni_回调()
{
JNIEnv*env=NULL;
jint retval=(*\u jamgr\u appVm)->GetEnv(\u jamgr\u appVm,(void**)和env,JNI\u版本1\u 4);
如果(retval==JNI_OK)
{
jclass cls=(*env)->GetObjectClass(env,_jamgr_appbj);
如果(cls)
{
jmethodID mid=(*env)->GetMethodID(env,cls,“toString”,“()Ljava/lang/String;”;
如果(中)
{
jobject strObj=(*env)->CallObjectMethod(env,jamgr,appObj,mid);
if(strObj)
{
const char*str=(*env)->GetStringUTFChars(env,strObj,NULL);
printf(“\n装入类为:%s\n”,str);
(*env)->释放StringUTFChars(env、strObj、str);
strObj=NULL;
}
mid=(*env)->GetMethodID(env,cls,“testMe”,“V”);
如果(中)
{
(*env)->CallVoidMethod(env,jamgr,appObj,mid);
}
}
}
}
返回返回;
}
这将满足您的需要,因为JNI方法在Java端不是静态的。但是,如果将它们设置为静态,那么
getMethodID
将无法工作,因为thiz是一个类,而不是
AgentMgrJni
的实例


还请注意,我通过
ReleasingUTFChars
修复了内存泄漏。。以及其他错误处理问题。我还在stop函数中调用了
DeleteGlobalRef

如果它确实打印了
“class com.example.AgentMgrService”
,您想让我拍摄控制台/调试器的屏幕截图吗?这是真实的、编译过的代码,但这是一个测试,我运行它是为了模拟在本机Android应用程序(即不是Ionic Cordova)上正常工作的行为。由于实际库的其余部分的设置方式,全局引用是必需的
jni_callback()
不是直接从Java调用方调用的,它发生在大约30秒后,在一堆其他工作线程被激发并完成它们的工作之后。。。。。。事实上,我甚至不确定调用
jni\u callback()
的线程是否与Java端启动的线程相同。我知道代码是空的,并且缺少错误检查,我只是想理解为什么我无法从
jni\u callback()
中获取
AgentMgrService.testMe()
,因为它返回零。我现在真的不在乎错误检查
#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

static JavaVM* _jamgr_appVm = NULL;
static jobject _jamgr_appObj = NULL;

int jni_callback();

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* aReserved)
{
    _jamgr_appVm = vm;
    return JNI_VERSION_1_4;
}

JNIEXPORT void JNICALL
Java_com_example_brandon_test_AgentMgrService_startAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    if (_jamgr_appVm == NULL)
    {
        (*env)->GetJavaVM(env, *_jamgr_appVm);
    }

    if (_jamgr_appObj == NULL) {
        _jamgr_appObj = (*env)->NewGlobalRef(env, thiz);
    }

    jni_callback();

}

JNIEXPORT void JNICALL
Java_com_example_brandon_test_AgentMgrService_stopAgentMgr(
        JNIEnv* env,
        jobject thiz,
        jstring config_data)
{
    (*env)->DeleteGlobalRef(env, _jamgr_appObj);
    _jamgr_appObj = NULL;
}

int jni_callback()
{
    JNIEnv* env = NULL;
    jint retval = (*_jamgr_appVm)->GetEnv(_jamgr_appVm, (void**) &env, JNI_VERSION_1_4);

    if (retval == JNI_OK)
    {
        jclass cls = (*env)->GetObjectClass(env, _jamgr_appObj);
        if (cls)
        {
            jmethodID  mid = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;");
            if (mid)
            {
                jobject strObj = (*env)->CallObjectMethod(env, _jamgr_appObj, mid);

                if (strObj)
                {
                    const char *str = (*env)->GetStringUTFChars(env, strObj, NULL);
                    printf("\nCalling class is: %s\n", str);
                    (*env)->ReleaseStringUTFChars(env, strObj, str);
                    strObj = NULL;
                }


                mid = (*env)->GetMethodID(env, cls, "testMe", "()V");

                if (mid)
                {
                    (*env)->CallVoidMethod(env, _jamgr_appObj, mid);
                }
            }
        }

    }

    return retval;
}