Concetti

Prima di iniziare

Questa guida presuppone che tu conosca già i concetti inerenti alla programmazione nativa e allo sviluppo Android.

Introduzione

Questa sezione fornisce una spiegazione dettagliata del funzionamento dell'NDK. L'NDK di Android è un insieme di strumenti che ti consentono di incorporare C o C++ ("codice nativo") nelle tue app Android. La possibilità di utilizzare il codice nativo nelle app Android può essere particolarmente utile per gli sviluppatori che vogliono eseguire una o più delle seguenti operazioni:

  • Trasferire le app tra piattaforme.
  • Riutilizza le librerie esistenti o fornisci le proprie librerie per il riutilizzo.
  • Aumentare le prestazioni in alcuni casi, in particolare in quelli con elevata intensità di calcolo, come i giochi.

Come funziona

Questa sezione presenta i componenti principali utilizzati nella creazione di un'applicazione nativa per Android e prosegue con la descrizione del processo di creazione e pacchettizzazione.

Componenti principali

Durante la creazione dell'app, dovresti conoscere i seguenti componenti:

  • Librerie condivise native: l'NDK crea queste librerie, o file .so, dal codice sorgente C/C++.

  • Librerie statiche native: l'NDK può anche creare librerie statiche o file .a, che puoi collegare ad altre librerie.

  • JNI (Java Native Interface): JNI è l'interfaccia tramite la quale i componenti Java e C++ interagiscono tra loro. Questa guida presuppone la conoscenza di JNI; per informazioni in merito, consulta le specifiche dell'interfaccia nativa Java.

  • Application Binary Interface (ABI): l'ABI definisce esattamente il modo in cui il codice macchina dell'app deve interagire con il sistema in fase di runtime. L'NDK crea file .so in base a queste definizioni. ABI diverse corrispondono ad architetture diverse: l'NDK include il supporto ABI per ARM a 32 bit, AArch64, x86 e x86-64. Per ulteriori informazioni, consulta la sezione ABI di Android.

  • Manifest: se scrivi un'app senza componenti Java, devi dichiarare la classe NativeActivity nel manifest. Per ulteriori dettagli su come eseguire questa operazione, consulta Utilizzare l'interfaccia native_activity.h.

Flusso

Il flusso generale per lo sviluppo di un'app nativa per Android è il seguente:

  1. Progetta la tua app, decidendo quali parti implementare in Java e quali implementare come codice nativo.

  2. Crea un progetto di app Android come faresti per qualsiasi altro progetto Android.

  3. Se stai scrivendo un'app solo nativa, dichiara la classe NativeActivity in AndroidManifest.xml. Per ulteriori informazioni, consulta la sezione Attività e applicazioni native.

  4. Crea un file Android.mk che descrive la libreria nativa, inclusi nome, flag, librerie collegate e file di origine da compilare nella directory "JNI".

  5. Se vuoi, puoi creare un file Application.mk configurando ABI di destinazione, toolchain, modalità di rilascio/debug e STL. Per ognuno di questi valori non specificati, vengono utilizzati rispettivamente i seguenti valori predefiniti:

    • ABI: tutte le ABI non ritirate
    • Modalità: release
    • STL: sistema
  6. Inserisci l'origine nativa nella directory jni del progetto.

  7. Utilizza ndk-build per compilare le librerie native (.so, .a).

  8. Crea il componente Java, producendo il file eseguibile .dex.

  9. Pacchettizza tutto in un file APK, contenente .so, .dex e altri file necessari per l'esecuzione dell'app.

Attività e applicazioni native

L'SDK Android fornisce una classe helper, NativeActivity, che ti consente di scrivere un'attività completamente nativa. NativeActivity gestisce la comunicazione tra il framework Android e il codice nativo, quindi non è necessario sottoclasse o chiamare i suoi metodi. Tutto ciò che devi fare è dichiarare che la tua applicazione è nativa nel file AndroidManifest.xml e iniziare a creare la tua applicazione nativa.

Un'applicazione Android che utilizza NativeActivity viene comunque eseguita nella propria macchina virtuale, protetta tramite sandbox da altre applicazioni. Puoi quindi continuare ad accedere alle API del framework Android tramite JNI. In alcuni casi, ad esempio per sensori, eventi di input e asset, l'NDK fornisce interfacce native che puoi utilizzare invece di chiamare attraverso JNI. Per ulteriori informazioni su questo supporto, consulta API native.

Indipendentemente dal fatto che tu stia sviluppando o meno un'attività nativa, ti consigliamo di creare i progetti con i tradizionali strumenti di creazione di Android. In questo modo è possibile garantire la creazione e il pacchetto delle app Android con la struttura corretta.

L'NDK di Android offre due opzioni per implementare l'attività nativa:

  • L'intestazione native_activity.h definisce la versione nativa della classe NativeActivity. Contiene l'interfaccia di callback e le strutture di dati necessarie per creare la tua attività nativa. Poiché il thread principale della tua applicazione gestisce i callback, le implementazioni dei callback non devono bloccare. Se vengono bloccati, potresti ricevere errori ANR (L'applicazione non risponde) perché il thread principale non risponde fino alla restituzione del callback.
  • Il file android_native_app_glue.h definisce una libreria helper statica basata sull'interfaccia native_activity.h. Genera un altro thread, che gestisce elementi come callback o eventi di input in un loop di eventi. Lo spostamento di questi eventi in un thread separato impedisce ai callback di bloccare il thread principale.

È disponibile anche l'origine <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c, che ti consente di modificare l'implementazione.

Per ulteriori informazioni su come utilizzare questa libreria statica, esamina l'applicazione di esempio di attività nativa e la relativa documentazione. Ulteriori informazioni sono disponibili anche nei commenti del file <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h.

Utilizza l'interfaccia native_activity.h

Per implementare un'attività nativa con l'interfaccia native_activity.h:

  1. Crea una directory jni/ nella directory principale del progetto. che memorizza tutto il codice nativo.

  2. Dichiara la tua attività nativa nel file AndroidManifest.xml.

    Poiché la tua applicazione non ha codice Java, imposta android:hasCode su false.

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

    Devi impostare l'attributo android:name del tag attività su nativeActivity.

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

    L'attributo android:value del tag meta-data specifica il nome della libreria condivisa contenente il punto di ingresso all'applicazione (ad esempio C/C++ main), omettendo il prefisso lib e il suffisso .so dal nome della libreria.

    <manifest>
      <application>
        <activity>
          <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>
    
  3. Crea un file per l'attività nativa e implementa la funzione denominata nella variabile A NativeActivity_onCreate. L'app chiama questa funzione all'avvio dell'attività nativa. Questa funzione, analoga a main in C/C++, riceve un puntatore a una struttura A NativeActivity, che contiene puntatori alle varie implementazioni di callback da scrivere. Imposta i puntatori della funzione di callback applicabili in ANativeActivity->callbacks alle implementazioni dei callback.

  4. Imposta il campo ANativeActivity->instance sull'indirizzo di qualsiasi istanza di dati specifici che vuoi utilizzare.

  5. All'inizio, implementa qualsiasi altra attività che vuoi venga eseguita.

  6. Implementa gli altri callback che hai impostato in ANativeActivity->callbacks. Per ulteriori informazioni su quando vengono richiamati i callback, consulta Gestione del ciclo di vita delle attività.

  7. Sviluppa il resto dell'applicazione.

  8. Crea un Android.mk file nella directory jni/ del progetto per descrivere il modulo nativo nel sistema di build. Per ulteriori informazioni, visita il sito Android.mk.

  9. Una volta ottenuto un file Android.mk, compila il codice nativo usando il comando ndk-build.

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. Crea e installa il tuo progetto Android come di consueto. Se il codice nativo si trova nella directory jni/, lo script di build pacchettizza automaticamente i file .so creati a partire dalla directory nell'APK.

Codice campione aggiuntivo

Per scaricare i campioni NDK, consulta gli esempi NDK.