Como fazer um plugin para Android em Java na Unity

Como fazer um plugin para Android em Java na Unity

Existem algumas estruturas possíveis para implementar um plugin Android na Unity. Quando utilizamos um plugin desenvolvido por terceiros é comum que a sua distribuição seja através de um arquivo AAR, que é uma biblioteca java para Android, junto com alguns scripts em C# para sua utilização. Esta é a opção mais simples, pois a Unity já reconhece o arquivo AAR como uma biblioteca Android e cuida do resto na compilação. Também é possível utilizar um arquivo JAR, mas não é um formato muito utilizado hoje em dia para desenvolvimento com Android, e até exige um pouco mais de configuração para ser utilizado na Unity.

Outra maneira de desenvolver um plugin dentro da Unity é mantendo o código java dentro do próprio projeto e, com ajuda de alguns outros arquivos, a Unity consegue configurar e compilar seu código Java como uma biblioteca para Android. Neste post não vou explicar como criar um arquivo AAR, mas é tão simples quanto criar um projeto de library no Android Studio e compilar para exportar o AAR, e a partir daí pode pular para a integração em C# na Unity.

Estrutura

Para usar o código java dentro da Unity precisamos montar a estrutura abaixo, assim a engine vai compilar o código corretamente como uma biblioteca Android. Qualquer plugin com código nativo deve sempre ser colocado dentro de uma pasta Plugins, e em uma sub-pasta com o nome da plataforma, no caso Android. Na pasta Android é onde fica a biblioteca Android, onde no exemplo abaixo é chamada native-test-lib. Agora precisamos de pelo menos mais 3 arquivos, que eu irei descrever em seguida.

├───Plugins
│   │
│   └───Android
│       │
│       └───native-test-lib
│           │   AndroidManifest.xml
│           │   build.gradle
│           │   project.properties
│           │
│           └───src
│               │
│               └───com
│                   │
│                   └───cicanci
│                       │
│                       └───unity
│                               NativeTest.java

Arquivo de configuração

No arquivo project.properties é necessário colocar apenas dois parâmetros para que o projeto seja reconhecido como uma biblioteca Android, a versão da API do Android que será a target (não é a versão mínima e não necessariamente a versão que será utilizada na compilação), e o parâmetro que habilita o projeto como library.

target=android-21
android.library=true

Android Manifest

O AndroidManifest.xml utilizado na library tem a o mínimo necessário para a definição deste arquivo: package e versão. O package é o mesmo que será utilizado no arquivo Java, e neste exemplo é com.cicanci.unity.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cicanci.unity" android:versionCode="1" android:versionName="1.0" >
    <application></application>
</manifest>

Compilação com gradle

Por fim, precisaremos apenas do arquivo build.gradle que também define o projeto como library e mostra para o compilador onde está o AndroidManifest.xml e o código Java (na pasta src). Aqui também temos definidas algumas versões para o SDK do Android utilizado para compilação e o mesmo target definido no arquivo project.properties. Este arquivo será compilado pela Unity junto com o gradle do projeto.

apply plugin: 'android-library'
android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
        }
    }
    compileSdkVersion 30
    buildToolsVersion '30.0.3'
    defaultConfig {
        targetSdkVersion 21
    }
}

Com todos os arquivos acima definidos e utilizando a estrutura mostrada no início do post, a Unity irá reconhecer o projeto como um plugin para Android, como podemos ver na imagem abaixo.

Código java

Eu quis manter este exemplo bem simples por que meu objetivo é demonstrar como criar um plugin e utilizá-lo na Unity, por isso o código abaixo faz algo bem simples: recebe e retorna strings e inteiros. O package aqui deve ser o mesmo definido no AndroidManifest.xml. Este é um exemplo simples, porém não existem limites para uma library Android aqui quando comparada com um aplicativo para Android feito fora da Unity.

package com.cicanci.unity;

public class NativeTest {
    private int counter = 0;
    private String message = "Hello from Android";

    public int getCounter() {
      return ++this.counter;
    }
    public String getMessage() {
      return this.message;
    }
    public void setCounter(int counter) {
      this.counter = counter;
    }
    public void setMessage(String message) {
      this.message = message;
    }
}

A localização do arquivo Java dentro do plugin deve ter ser em uma estrutura de pastas que reflitam o package. Como neste exemplo o package é com.cicanci.unity, o arquivo NativeTest.java deve ficar dentro de Plugins/Android/native-test-lib/src/com/cicanci/unity/ - a localização do plugin Android na Unity + a pasta que o arquivo build.gradle vai procurar o código Java que é src + estrutura que reflete o package no AndroidManifest.xml.

Implementação no C#

A parte final do plugin é sua utilização na Unity através do C#, e nisso a engine ajuda bastante com a classe AndroidJavaObject. Com esta class iremos criar nosso objeto com o nome completo da classe (package + nome da classe). Após criar o objeto podemos executar métodos da classe Java utilizando o método Call(), que também possui parâmetro para retornar um tipo quando o método Java não é void.

#if UNITY_ANDROID
using UnityEngine;

public class NativeTestAndroid {
    private readonly AndroidJavaObject _nativeTestClass;

    public NativeTestAndroid() {
        _nativeTestClass = new AndroidJavaObject("com.cicanci.unity.NativeTest");
    }
    public int GetCounter() {
        return _nativeTestClass.Call<int>("getCounter");
    }
    public string GetMessage() {
        return _nativeTestClass.Call<string>("getMessage");
    }
    public void SetCounter(int counter) {
        _nativeTestClass.Call("setCounter", counter);
    }
    public void SetMessage(string message) {
        _nativeTestClass.Call("setMessage", message);
    }
}
#endif

Não existe muito segredo, é realmente bem simples executar um código de uma library Android em Java no C# da Unity. Basta prestar atenção no tipo do retorno do método e no seu nome na hora de definir os métodos no C#. Outra dica é colocar seu código C# dentro de um #if UNITY_ANDROID para evitar erros de compilação em outras plataformas já que a classe AndroidJavaObject existe apenas quando a plataforma é Android na Unity.

Conclusão

Neste post quis mostrar como é criar um plugin para Android na Unity e, a partir deste template é possível fazer muitas coisas. Na época da Unity 5 era mais comum criar plugins para Android, já que a engine tinha um suporte bem limitado para esta plataforma, isso mudou bastante nas versões posteriores. Hoje muito do que você precisa já tem suporte para Android na Unity, porém pode ser que seja limitado ou que você queira ter controle sobre o código - nestes casos é bom fazer seu próprio plugin.

Quando preciso desenvolver um plugin para Android na Unity eu geralmente crio um projeto novo no Android Studio e faço tudo por lá, inclusive com um aplicativo de testes. Desta forma é possível utilizar todas as ferramentas de desenvolvimento presentes na IDE antes de ir para a Unity, onde seria mais difícil e nada prático desenvolver uma library Android mais complexa. Eu prefiro exportar o projeto como um arquivo AAR, porém para algo simples e pequeno eu acabo deixando o código dentro da Unity e evito manter um projeto Android apenas para esta finalidade.

Todo o código deste post e um exemplo de uso está disponível neste repositório no GitHub. Pretendo escrever outro post mostrando como fazer o mesmo plugin para iOS e sua utilização na Unity.

comments powered by Disqus