用JNI从C++调用一个没有参数的JAVA方法

5
请耐心等待,我是一名iPhone开发人员,对于整个Android系统还有些困惑。
我有一些C++方法被cocos2d-x的CCMenuItem调用。因此,根据文档,我无法发送任何参数。
我需要使用Android浏览器打开一个URL,这将要求我调用一个JAVA函数来启动新意图。
我知道我需要创建一个VM,但下面的代码给我带来了错误:
jni/../../Classes/OptionsScene.cpp:184: error: 'JNI_CreateJavaVM' was not declared in this scope 我看了这个线程:Calling a java method from c++ in Android 但他使用了参数,而我不能这样做。我也不知道在他的代码中哪里可以找到它们,以便自己制作。
我不知道“Find Class”方法中的字符串应该是什么。此外,我认为在每个需要调用的方法中创建一个新的VM实例非常糟糕。如何创建一个单例以在各个领域使用?
这是我的C++代码,由我的菜单项调用:
#include <jni.h>
...
JavaVM *vm; // Global
...
void OptionsScene::website(){
JNIEnv *env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;

jint result = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args); // This line still errors

jclass clazz = env->FindClass("com/prndl/project/WebExecute");
jmethodID method = env->GetMethodID(clazz, "website", "(Ljava/lang/String;)V");
env->CallVoidMethod(NULL,method);

vm->DestroyJavaVM();

我需要调用的是这个JAVA方法:

public class WebExecute extends Activity{
    public void website(){
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
        startActivity(browserIntent);
    }
}

说实话,我在这方面很苦恼,需要帮助。谢谢。


你现在有哪些行出现错误?只有 JNI_CreateJavaVM 这一行还是其他行也有?你是否仔细检查了编译器/IDE设置,确保包含 jni.hJDK_HOME/include 目录已经在搜索路径中?对于 JDK_HOME/include/android 目录(或者在 Android JDK 中称为操作系统特定目录的目录),也是同样的情况吗? - QuantumMechanic
你是否遇到了编译错误? - IgorGanapolsky
2个回答

4
如果您想调用一个不带任何参数的Java方法,格式如下:jmethodID mid = env->GetStaticMethodID(myClass, "myMethod", "()V"); ()表示该方法不带任何参数。 V表示它返回void。如果该方法返回类型为String的对象,则应使用Ljava/lang/String;

1

有很多事情...

1. 假设你已经声明了 JNIEnv* env;,并且你正在使用 C++,那么你应该使用 env->FindClass(someString),而不是你目前的方式。如果你在使用 C 语言,你会使用 FindClass(env, someString),但是在 C++ 中,你需要使用 env->FindClass(someString)
2. 在 FindClass 中使用的字符串是完全限定路径名,但是分隔符要用 / 而不是 .。例如,如果类是包中的 Foo 类,包名为 bar.baz.quux,则完全限定名称为 bar.baz.quux.Foo,而你需要给 FindClass 的字符串是 bar/baz/quux/Foo
3. 每个 C++ 进程只能创建一个 JVM。我相信你需要创建一个单独的 JVM。因此,JavaVM* vm 需要成为全局变量(或者至少可以被所有需要使用它的东西访问)。与调用 JNI_CreateJavaVM() 的线程处于同一 C++ 线程中的所有内容都将使用由该调用填充的 JNIEnv *。想要使用 JVM 的每个其他线程都需要调用 AttachCurrentThread,它将绑定该线程到 JVM 并填充一个对于该线程有效的新的 JNIEnv *
4. 你是否仔细检查了编译器/IDE 设置,确保 JDK_HOME/include 目录(其中包含 jni.h)在包含搜索路径中?同样适用于 JDK_HOME/include/android 目录(或者在 Android JDK 中称为操作系统特定目录的目录)?

一个非常有用的资源是JNI书籍

但是在阅读时要小心,因为一些示例是用C编写的,而另一些则是用C++编写的,所以请确保您了解调用约定的区别。


我已经更新了我的原始代码。尽管我已经包含了jni.h,但它仍然显示JNI_CreateJavaVM在此范围内未声明。另外,由于我没有为website()设置参数,我是否应该在env->CallVoidMethod()的第一个参数中使用NULL? - PRNDL Development Studios
在Linux上使用g++进行一些实验表明,void **的东西是一个误导(我对C++有点生疏)。作为测试,我声明了一个void foo(void *)函数,然后像这样调用它:int i = 42; foo(&i);编译器甚至没有发出警告,更不用说错误了。因此,我认为void **转换的存在或不存在并不相关。 - QuantumMechanic
2
websiteж–№жі•жІЎжңүеҸӮж•°пјҢеӣ жӯӨзұ»еһӢзӯҫеҗҚеә”дёә"()V"иҖҢдёҚжҳҜ"(Ljava/lang/String;)V"гҖӮ - Driss Bounouar

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