使用 JNI 从 Cocoa 调用 Java 类函数
我真的很难弄清楚如何使用 JNI 从 Objective-C 调用 Java 函数.
I'm really struggling to figure out how I can call a Java function from Objective-C using JNI.
首先我应该说我对 Java 知之甚少,但对 Obj-C 非常熟悉.我有一个 Java 类和一个方法,我需要从我的应用程序包中调用它.jar 位于包中的 Resources 文件夹内,我将 NSJavaRoot
设置为 Content/Resources
,检查 NSJavaNeeded
并检查 NSJavaPath
包含 2 个 jar 文件的名称(主要的一个和一个依赖项).
I should start by saying I don't know anything much about Java but am very familiar with Obj-C. I have a single Java class with a single method that I need to call from my app bundle. The jar is inside the Resources folder in the bundle and I have NSJavaRoot
set to Content/Resources
, NSJavaNeeded
is checked and NSJavaPath
contains the names of 2 jar files (main one and one dependency).
我正在使用对 JNI_CreateJavaVM
的调用来启动 VM,然后尝试使用 NSClassFromString
查找类,这感觉不对,但这是我在我的搜索.我相信这种方法在使用已弃用的 Java 桥接器时是正确的,但我找不到任何使用 JNI 的示例或参考.
I'm firing up the VM using a call to JNI_CreateJavaVM
and then attempting to find the class using NSClassFromString
which feels wrong but is the only method I have found in my search. I believe this method is correct when using the deprecated Java bridge but I cannot find any examples or references that use JNI.
我的 Java 类如下所示:
My Java class looks like this:
package foo;
public class bar {
public function dostuff() {
}
}
我需要在应用程序流程中调用一次 dostuff()
.有谁知道如何做到这一点?
I need to call dostuff()
once as part of the app flow. Does anyone have any ideas how to do this?
谢谢,J
推荐答案
由于 JavaBridge 已被弃用,您将不得不使用 JNI 来完成这一切.在 MacOS 上,您需要将 JavaVM.framework 添加到您的项目中,并且从您的源文件中,您要查找的标头是:
Since the JavaBridge has been deprecated, you are going to have to do this all with JNI. On MacOS, you'll want to add the JavaVM.framework to your project, and from your source files, the header you're looking for is:
#import <JavaVM/jni.h>
接下来您需要设置 JavaVM.这可能很重要,具体取决于您的类路径和其他要求,但您走在正确的轨道上,因为这是您用来创建 JVM 的函数:
Next you need to set up the JavaVM. This can be non-trivial, depending on your classpath and other requirements, but you're on the right track as this is the function you use to create the JVM:
JNI_CreateJavaVM(JavaVM **pJVM, void **pJNIEnv, void *args);
接下来,您需要获取对您的类 foo.bar 的引用.这可以使用从 JNI_CreateJavaVM 传递的 pJNIEnv 来完成.你会想打电话:
Next you'll want to get a reference to your class foo.bar. This you can do using the pJNIEnv that was passed out from JNI_CreateJavaVM. You'll want to call:
jclass myClass = JNIEnv->FindClass(JNIEnv, "foo/bar"); // Note the slashes replacing the dots...
假设一切设置正确,您将获得对您的班级的引用.假设 foo.bar 有一个默认的无参数构造函数,你可以得到它的一个实例,像这样:
Assuming everything is set up right, you'll get back a reference to your class. Assuming for the moment that foo.bar has a default parameterless constructor, you can get an instance of it, like this:
jobject myFooBar = JNIEnv->NewObject(JNIEnv, myClass);
现在您需要获取 doStuff 方法的 methodID.为此,您需要它的方法签名,您可以通过调用 javap 获得,如下所示:
Now you need to get the methodID of your doStuff method. To do this, you'll need it's method signature, which you can get by calling javap, like this:
% javap -s foo.bar
应该产生这样的输出:
Compiled from "bar.java"
public class foo.bar extends java.lang.Object{
public foo.bar();
Signature: ()V
public void doStuff();
Signature: ()V
}
然后您可以使用它来获取方法ID,您需要调用它.像这样:
Then you can use that to get the methodID, which you'll need to call it. Like so:
jmethodID mid = JNIEnv->GetMethodID(JNIEnv, myClass, "doStuff", "()V");
假设所有这些事情都正确,那么你可以这样调用方法:
Assuming all these things have gone right, then you can call the method like this:
JNIEnv->CallVoidMethod(JNIEnv, myFooBar, mid);
并且该方法应该被调用.在任何这些阶段之后,您可能需要检查 VM 以查看是否存在异常.您可以通过以下方式检查是否发生异常:
and the method should get called. After any of these stages, you probably want to check with the VM to see if there was an exception. You can check to see if an exception occurred by doing this:
if (JNIEnv->ExceptionCheck(JNIEnv))
{
// Handle the exception...
}
如果你想要实际的 throwable,你可以使用 ExceptionOccurred JNI 方法得到它.
If you want the actual throwable, you can get it using the ExceptionOccurred JNI method.
所以,它是最精简的:如何使用 JNI 从 Cocoa 调用 Java 方法.您将需要阅读 JNI 文档,尤其是有关理解全局引用和本地引用之间差异的部分.(即让你的 Cocoa 端引用持续足够长的时间,以便在它们创建的范围之外被调用.)事实上,有一整章是关于常见错误和陷阱的,其中很多你都会遇到.
So, there it is at it's most stripped down: how you call a Java method from Cocoa with JNI. You will want to read up on the JNI docs, espeically the parts about understanding the differences between global and local references. (i.e. making your Cocoa-side references last long enough to be called outside of the scope in which they were created.) In fact, there's a whole chapter on common mistakes and pitfalls, many of which you will hit.
http://java.sun.com/docs/books/jni/
祝你好运!
相关文章