Como criar métodos nativos

O J2ObjC oferece suporte à incorporação de Objective-C em métodos nativos do Java, muito semelhante à incorporação do JavaScript com o JSNI do GWT. A principal diferença entre a incorporação J2ObjC e a do GWT é que o J2ObjC usa /*-[ e ]-*/ para delinear o código Objective-C. Essa instalação é chamada de OCNI (interface nativa do Objective-C) para se diferenciar do JSNI do GWT.

Confira um exemplo da versão de java.lang.System da biblioteca de emulação JRE:

  public static native long currentTimeMillis() /*-[
    // Use NSDate
    return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
  ]-*/;

O J2ObjC copia o comentário, menos os delimitadores, para criar o corpo do método:

  + (long long int)currentTimeMillis {
    // Use NSDate
    return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
  }

Importações nativas

O J2ObjC verifica o código Java que está sendo traduzido para adicionar diretivas #import às dependências, bem como importar o framework Foundation. No entanto, qualquer importação necessária apenas para o código nativo precisa ser adicionada separadamente. Para adicionar importações, inclua uma seção OCNI acima da primeira classe no arquivo de origem Java e especifique as importações lá, por exemplo:

  package my.project;

  /*-[
  #import "java/lang/NullPointerException.h"
  ]-*/

  public class Test {
    native void test() /*-[
      @throw [[JavaLangNullPointerException alloc] init];
    ]-*/;
  }

A importação é necessária no exemplo acima porque o único lugar a que esse tipo é referenciado é no código nativo.

Blocos nativos

No corpo de uma classe, o J2ObjC verifica se há blocos OCNI. Esses blocos são adicionados sem modificações ao arquivo traduzido, na mesma posição em relação aos membros da classe traduzidas. Confira um exemplo:

  /*-[
    static void log(NSString *msg) {
      NSLog(@"%@", msg);
    }
  ]-*/;

Essa função C pode ser invocada por qualquer método nativo declarado após esse bloco OCNI.

Uma variante especial desse bloco OCNI insere código no cabeçalho gerado em vez do arquivo .m: /*-HEADER[...]

Como invocar métodos Java do código nativo

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);
]-*/;

Como acessar campos a partir do código nativo

Para ler um campo de instância, use myInstanceField_ ou self->myInstanceField_. O sufixo à direita evita um conflito com métodos com o mesmo nome.

Observe que os campos com nomes reservados terão dois sublinhados. Por exemplo, um campo chamado "id" é legal em Java, mas não em Objective C. Quando traduzido, o campo será chamado de "id__". Portanto, verifique os arquivos gerados se houver erros do compilador "no-tal-field".

Para gravar em um campo de instância de objeto, use JSNIExample_set_myInstanceField(string).

Ler um campo estático: JSNIExample_get_myStaticField()

Gravar um campo estático: JSNIExample_set_myStaticField(value)

J2ObjC e GWT

Delimitadores diferentes foram escolhidos para que, na próxima versão do J2ObjC, os comentários do JSNI do GWT fossem ignorados (anteriormente, os mesmos delimitadores eram usados como GWT). Isso significa que uma única origem Java pode ter métodos nativos com implementações de Objective-C, GWT e Android (via JNI):

  static native void log(String text) /*-{ // left-brace for JavaScript
    console.log(text);
  }-*/ /*-[                                // left-bracket for Objective-C
     NSLog(@"%@", text);
  ]-*/;

J2ObjC e Android

As implementações de métodos nativos J2ObjC e Android "simplesmente funcionam", porque os métodos nativos do Android são implementados em um arquivo JNI C ou C++ separado. Todos os comentários OCNI em classes Java são removidos quando compilados por javac para Android ou qualquer outra plataforma Java.