J2ObjC 支持将 Objective-C 嵌入到 Java 原生方法中,这与 GWT 的 JSNI 支持 JavaScript 嵌入的方式非常相似。J2ObjC 嵌入与 GWT 之间的主要区别在于 J2ObjC 使用 /*-[
和 ]-*/
来划分 Objective-C 代码。此功能称为 OCNI(Objective-C 原生接口),旨在与 GWT 的 JSNI 区分开来。
以下是 JRE 模拟库的 java.lang.System
版本中的一个示例:
public static native long currentTimeMillis() /*-[
// Use NSDate
return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
]-*/;
J2ObjC 会复制注释(减去分隔符),以创建方法正文:
+ (long long int)currentTimeMillis {
// Use NSDate
return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
}
原生导入
J2ObjC 会扫描正在转换的 Java 代码,以为其依赖项添加 #import 指令,同时导入 Foundation 框架。不过,仅需单独添加原生代码所需的任何导入项。如需添加导入,请在 Java 源文件中的第一个类上方添加一个 OCNI 部分,并在该类中指定导入内容;例如:
package my.project;
/*-[
#import "java/lang/NullPointerException.h"
]-*/
public class Test {
native void test() /*-[
@throw [[JavaLangNullPointerException alloc] init];
]-*/;
}
在上面的示例中,导入操作是必要的,因为引用该类型的唯一位置是在原生代码中。
原生块
在类正文中,J2ObjC 会扫描是否存在 OCNI 块。这些块会原封不动地添加到翻译后的文件,且位于与翻译的类成员的相对位置。示例如下:
/*-[
static void log(NSString *msg) {
NSLog(@"%@", msg);
}
]-*/;
此 C 函数可通过在此 OCNI 块之后声明的任何原生方法调用。
此 OCNI 代码块的一个特殊变体会在生成的头文件(而不是 .m 文件中)中插入代码:/*-HEADER[...]
从原生代码调用 Java 方法
public native void bar(JSNIExample x, String s) /*-[
// Call instance method instanceFoo() on this
[self instanceFooWithNSString:s];
// Call instance method instanceFoo() on x
[x instanceFooWithNSString:s];
// Call static method staticFoo()
JSNIExample_staticFooWithNSString_(s);
]-*/;
通过原生代码访问字段
如需读取实例字段,请使用 myInstanceField_
或 self->myInstanceField_
。末尾的后缀可避免与同名方法发生冲突。
请注意,具有预留名称的字段将带有两个下划线。例如,名为“id”的字段在 Java 中是合法的,但在 Objective C 中则不然。翻译后,该字段将命名为“id__”。因此,请检查生成的文件是否存在“无此类字段”编译器错误。
如需写入对象实例字段,请使用 JSNIExample_set_myInstanceField(string)
读取静态字段:JSNIExample_get_myStaticField()
写入静态字段:JSNIExample_set_myStaticField(value)
J2ObjC 和 GWT
选择了不同的分隔符,以便在下一个 J2ObjC 版本中忽略 GWT JSNI 注释(之前使用的是与 GWT 相同的分隔符)。这意味着单个 Java 源代码可以具有具有 Objective-C、GWT 和 Android(通过 JNI)实现的原生方法:
static native void log(String text) /*-{ // left-brace for JavaScript
console.log(text);
}-*/ /*-[ // left-bracket for Objective-C
NSLog(@"%@", text);
]-*/;
J2ObjC 和 Android
J2ObjC 和 Android 原生方法实现“照常运行”,因为 Android 原生方法在单独的 JNI C 或 C++ 文件中实现。当针对 Android 或任何其他 Java 平台的 javac 编译时,Java 类中的所有 OCNI 注释都会被移除。