Conceitos

Antes de começar

Este guia presume que você já conheça bem os conceitos inerentes à programação nativa e ao desenvolvimento para Android.

Introdução

Esta seção traz uma explicação de nível avançado sobre como o NDK funciona. O Android NDK é um conjunto de ferramentas que permitem incorporar C ou C++ (“código nativo”) em apps Android. A capacidade de usar código nativo em apps Android pode ser muito útil para desenvolvedores que querem:

  • portar apps entre plataformas;
  • reutilizar bibliotecas existentes ou fornecer as próprias para reutilização;
  • melhorar o desempenho em determinados casos, em especial nos de computação intensa, como jogos.

Como funciona

Esta seção apresenta os principais componentes usados na compilação de um app nativo para Android e descreve o processo de compilação e empacotamento.

Principais componentes

É necessário compreender os seguintes componentes durante ao criar seu app:

  • Bibliotecas compartilhadas nativas: o NDK cria essas bibliotecas ou arquivos .so, a partir do código-fonte C/C++.
  • Bibliotecas estáticas nativas: o NDK também pode compilar bibliotecas estáticas ou arquivos .a que podem ser vinculados a outras bibliotecas.
  • Java Native Interface (JNI): a JNI é a interface de comunicação entre os componentes Java e C++. Este guia requer conhecimentos sobre JNI. Para mais informações sobre esse recurso, consulte a Especificação da Java Native Interface (link em inglês).
  • Interface Binária de App (ABI): a ABI define exatamente como deverá ser a interação entre o código de máquina do app e o sistema no ambiente de execução. O NDK compila arquivos .so de acordo com essas definições. Diferentes ABIs correspondem a diferentes arquiteturas: o NDK é compatível com ABI para ARM de 32 bits, AArch64, x86 e x86-64. Para mais informações, consulte Gerenciamento de ABI.
  • Manifesto: se você estiver criando um app sem componente Java, precisará declarar a classe NativeActivity no manifesto. Atividades e apps nativos fornece mais detalhes sobre como fazer isso, em "Como usar a interface native_activity.h".

Fluxo

O fluxo geral para desenvolver um app nativo para Android é o seguinte:

  1. Projete o app e decida que partes serão implementadas em Java e em código nativo.

    Observação: embora seja possível evitar totalmente o uso de Java, a estrutura Java para Android é útil para determinadas tarefas, como controlar a tela e a IU.

  2. Crie um projeto de app para Android normalmente.
  3. Se você estiver criando um app somente nativo, declare a classe NativeActivity em AndroidManifest.xml. Para mais informações, consulte Atividades e apps nativos.
  4. Crie um arquivo Android.mk que descreva a biblioteca nativa, incluindo nome, sinalizações, bibliotecas vinculadas e arquivos de origem a serem compilados no diretório “JNI”.
  5. Você também pode criar um arquivo Application.mk configurando as ABIs de destino, conjuntos de ferramentas, modo de liberação/depuração e STL. Para qualquer um desses itens que você não especificar, os valores padrão a seguir serão usados, respectivamente:
    • ABI: todas as ABIs não obsoletas
    • Conjunto de ferramentas: clang
    • Modo: liberação
    • STL: system
  6. Coloque o código-fonte nativo no diretório jni do projeto.
  7. Use o ndk-build para compilar as bibliotecas nativas (.so, .a).
  8. Crie o componente Java, produzindo o arquivo executável .dex.
  9. Agrupe tudo em um arquivo APK, contendo .so, .dex e outros arquivos necessários para a execução do app.

Atividades e apps nativos

O SDK do Android fornece uma classe auxiliar, NativeActivity, que permite que você grave uma atividade completamente nativa. NativeActivity gerencia a comunicação entre a estrutura do Android e seu código nativo, de modo que você não precise criar subclasses nem chamar os métodos. Basta declarar o app como nativo no arquivo AndroidManifest.xml e começar a desenvolvê-lo.

Os aplicativos para Android que usam NativeActivity ainda podem ser executados na própria máquina virtual, no sandbox de outros apps. Portanto, você ainda pode acessar as APIs do framework do Android por meio do JNI. No entanto, em certos casos, como para sensores, eventos de entrada e recursos, o NDK fornece interfaces nativas que você pode usar em vez de chamar o JNI. Para mais informações sobre essa compatibilidade, consulte APIs nativas do Android NDK.

Independentemente de estar desenvolvendo ou não uma atividade nativa, recomendamos que você crie projetos com as ferramentas de compilação tradicionais do Android. Isso ajuda a garantir a compilação e o empacotamento de apps Android com a estrutura correta.

O Android NDK fornece duas possibilidades para implementar atividades nativas:

  • O arquivo principal native_activity.h define a versão nativa da classe NativeActivity. Ele contém a interface de callback e as estruturas de dados necessárias para criar a atividade nativa. Como a linha de execução principal do app lida com os callbacks, suas implementações de callback não podem gerar bloqueios. Se isso acontecer, você poderá receber erros do tipo "O app não está respondendo" (ANR, na sigla em inglês), porque a linha de execução principal não responderá até o retorno do callback.
  • O arquivo android_native_app_glue.h define uma biblioteca auxiliar estática compilada no topo da interface native_activity.h. Ele gera outra linha de execução, que gerencia elementos como callbacks ou eventos de entrada em um loop de evento. Mover esses eventos para uma linha de execução separada impede que qualquer callback bloqueie sua linha de execução principal.

A fonte <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c também está disponível, permitindo que você modifique a implementação.

Para mais informações sobre como usar essa biblioteca estática, veja o exemplo de app de atividade nativa e a documentação correspondente. Para mais informações, leia também os comentários no arquivo <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h.

Usar a interface native_activity.h

Para implementar uma atividade nativa com a interface native_activity.h:

  1. Crie um diretório jni/ no diretório raiz do projeto. Esse diretório armazenará todos os códigos nativos.
  2. Declare sua atividade nativa no arquivo AndroidManifest.xml.
  3. Como seu app não tem código em Java, defina android:hasCode como false.

        <application android:label="@string/app_name" android:hasCode="false">
        

    Defina o atributo android:name da tag de atividade como NativeActivity.

        <activity android:name="android.app.NativeActivity"
                    android:label="@string/app_name">
        

    Observação: você pode criar uma subclasse para NativeActivity. Se fizer isso, use o nome da subclasse em vez de NativeActivity.

    O atributo android:value da tag meta-data especifica o nome da biblioteca compartilhada que contém o ponto de entrada para o app (como main em C/C++), omitindo o prefixo lib e o sufixo .so do nome da biblioteca.

                  <meta-data android:name="android.app.lib_name"
                    android:value="native-activity" />
                    <intent-filter>
                      <action android:name="android.intent.action.MAIN" />
                      <category android:name="android.intent.category.LAUNCHER" />
                    </intent-filter>
                  </activity>
                </application>
              </manifest>
        
  4. Crie um arquivo para a atividade nativa e implemente a função nomeada na variável ANativeActivity_onCreate. O app chama essa função quando a atividade nativa é iniciada. Essa função, análoga a main em C/C++, recebe um ponteiro para uma estrutura ANativeActivity, que contém ponteiros de função para as diferentes implementações de callback que você precisa escrever. Defina os ponteiros aplicáveis da função de callback em ANativeActivity->callbacks para as implementações dos callbacks.
  5. Defina o campo ANativeActivity->instance como o endereço de qualquer instância de dados específicos que você quer usar.
  6. Implemente tudo o que a atividade fará depois de iniciada.
  7. Implemente os demais callbacks definidos em ANativeActivity->callbacks. Para saber mais sobre quando os callbacks são chamados, consulte Gerenciamento do ciclo de vida da atividade.
  8. Desenvolva o restante do app.
  9. Crie um Android.mk file no diretório jni/ do projeto para descrever seu módulo nativo para o sistema de compilação. Para mais informações, consulte Android.mk.
  10. Depois de criar um arquivo Android.mk, compile seu código nativo usando o comando ndk-build.
  11.     $ cd <path>/<to>/<project>
        $ <ndk>/ndk-build
        
  12. Compile e instale seu projeto para Android normalmente. Se o código nativo estiver no diretório jni/, o script de compilação empacotará automaticamente os arquivos .so compilados a partir dele no APK.

Outras amostras de código

Para fazer o download de amostras do NDK, consulte Amostras do NDK (link em inglês).