【问题标题】:Calling a JAVA method from C++ with JNI, no parameters使用 JNI 从 C++ 调用 JAVA 方法,无参数
【发布时间】:2012-07-04 12:29:21
【问题描述】:

请多多包涵,我是一名 iPhone 开发人员,这整个 android 让我有点困惑。

我有一些从 cocos2d-x CCMenuItem 调用的 c++ 方法。因此,根据文档,我无法发送任何参数。

我需要用 android 浏览器打开一个 url,这需要我调用一个 JAVA 函数来启动一个新的 Intent。

我知道我需要创建一个虚拟机,但是下面的代码给了我错误:

jni/../../Classes/OptionsScene.cpp:184:错误:“JNI_CreateJavaVM”是 未在此范围内声明

我在看这个帖子:Calling a java method from c++ in Android

但他使用参数,而我不能这样做。而且我看不到这些在他的代码中的位置,只是我自己制作的。

我不知道“查找类”方法中的字符串应该是什么。 另外,我认为在我需要调用的每个方法中创建一个新的 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 设置以确保 JDK_HOME/include 目录(包含 jni.h)在包含搜索路径中? JDK_HOME/include/android 目录也一样(或在 Android JDK 中调用 JDK_HOME/include 中的任何特定操作目录)?
  • 您是否遇到编译错误?

标签: java android c++ jvm java-native-interface


【解决方案1】:

如果您正在查看如何调用不接受任何参数的 java 方法,格式为 jmethodID mid = env-&gt;GetStaticMethodID(myClass, "myMethod", "()V");

() 是你告诉它不接受任何参数的方式。

V说它返回无效。如果方法返回String 类型的对象,则应使用Ljava/lang/String;

【讨论】:

    【解决方案2】:

    很多东西...

    1. 给定声明 JNIEnv* env;,并假设您使用 C++,您将其用作 env-&gt;FindClass(someString)不是您是如何做到的。如果是 C,您将使用 FindClass(env, someString),但在 C++ 中,您使用 env-&gt;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 并填写一个 new JNIEnv * 对该线程有效。
    4. 您是否仔细检查了您的编译器/IDE 设置以确保JDK_HOME/include 目录(其中包含jni.h)在包含搜索路径中? JDK_HOME/include/android 目录(或在 Android JDK 中调用 JDK_HOME/include 中的任何特定操作目录)是否相同?

    一个非常有用的资源是The JNI book

    但在阅读时要小心,因为有些示例是用 C 语言编写的,有些是用 C++ 编写的,因此请确保您了解调用约定的不同之处。

    【讨论】:

    • 我更新了上面的原始代码。它仍然说 JNI_CreateJavaVM 没有在这个范围内声明,即使我已经包含了 jni.h。另外,由于我没有 website() 的参数,我应该使用 NULL 作为 env->CallVoidMethod() 的第一个参数吗?
    • 在 Linux 上对 g++ 的一些实验表明 void ** 的东西是一个红鲱鱼(我对 C++ 生疏了)。在我测试时,我声明了void foo(void *) 函数,然后像这样调用它:int i = 42; foo(&amp;i);,编译器甚至没有给出警告,更不用说错误了。所以我认为void ** 演员的存在与否无关紧要。
    • website 方法没有参数,所以类型签名应该是"()V"而不是"(Ljava/lang/String;)V"
    猜你喜欢
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多