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 para Android. A capacidade de usar código nativo em apps para 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 criaçã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 criar 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 ABIs do Android. - Manifesto: se você estiver criando um app sem componente Java, precisará declarar a
classe
NativeActivity
no manifesto. Consulte Usar a interface native_activity.h para ver mais detalhes sobre como fazer isso.
Fluxo
O fluxo geral para desenvolver um app nativo para Android é o seguinte:
- 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.
- Crie um projeto de app Android normalmente.
- Se você estiver criando um app somente nativo, declare a classe
NativeActivity
emAndroidManifest.xml
. Para mais informações, consulte Atividades e apps nativos. - 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”. - 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
- Coloque o código-fonte nativo no diretório
jni
do projeto. - Use o ndk-build para compilar as bibliotecas nativas (
.so
,.a
). - Crie o componente Java, produzindo o arquivo executável
.dex
. - Agrupe tudo em um arquivo APK, contendo
.so
,.dex
e outros arquivos necessários para a execução do app.
Atividades e aplicativos 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. Porém, 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.
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 classeNativeActivity
. 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 interfacenative_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
:
- Crie um diretório
jni/
no diretório raiz do projeto. Esse diretório armazenará todos os códigos nativos. - Declare sua atividade nativa no arquivo
AndroidManifest.xml
. - 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 amain
em C/C++, recebe um ponteiro para uma estruturaANativeActivity
, 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 emANativeActivity->callbacks
para as implementações dos callbacks. - Defina o campo
ANativeActivity->instance
como o endereço de qualquer instância de dados específicos que você quer usar. - Implemente tudo o que a atividade fará depois de iniciada.
- 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. - Desenvolva o restante do app.
- Crie um
Android.mk file
no diretóriojni/
do projeto para descrever seu módulo nativo para o sistema de compilação. Para mais informações, consulte Android.mk. - Depois de criar um arquivo
Android.mk
, compile seu código nativo usando o comandondk-build
. - Crie 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.
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>
$ cd <path>/<to>/<project> $ <ndk>/ndk-build
Outro exemplo de código
Para fazer o download de amostras do NDK, consulte Amostras do NDK (link em inglês).