gpt4 book ai didi

java - Android JNI GetMethodID() 失败

转载 作者:太空宇宙 更新时间:2023-11-04 03:20:47 24 4
gpt4 key购买 nike

我正在尝试构建一个 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 方法,但不能调用我定义的方法?我还没有尝试将任何东西设为静态,但我不确定这是否有帮助。

最佳答案

你的问题的答案在于你的本地方法是否是静态的..

在 JNI 中,如果你有

public static native void startAgentMgr(String agentMgrConfig);
public static native void stopAgentMgr();

在java端,当你调用这个方法时,this对象将是一个CLASS而不是一个INSTANCE..毕竟这个方法是静态的,它没有this.

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

public native void startAgentMgr(String agentMgrConfig);
public native void stopAgentMgr();

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

例子:

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!";
}
}

native 代码:

#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;
}

这将执行您想要的操作,因为 JNI 方法在 Java 端不是静态的。但是,如果您将它们设为静态,则 getMethodID 将无法正常工作,因为 thiz 是一个类而不是 AgentMgrJni 的实例。

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

关于java - Android JNI GetMethodID() 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46555179/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com