Konzepte

Vorbereitung

In diesem Leitfaden wird davon ausgegangen, dass Sie bereits mit Konzepten der nativen Programmierung und der Android-Entwicklung vertraut sind.

Einführung

In diesem Abschnitt wird die Funktionsweise des NDK allgemein erläutert. Das Android-NDK umfasst eine Reihe von Tools, mit denen Sie C oder C++ ("nativer Code") in Ihre Android-Apps einbetten können. Die Möglichkeit, nativen Code in Android-Apps zu verwenden, kann besonders für Entwickler nützlich sein, die eine oder mehrere der folgenden Aufgaben ausführen möchten:

  • Ihre Apps auf andere Plattformen übertragen
  • Sie können vorhandene Bibliotheken wiederverwenden oder eigene Bibliotheken zur Wiederverwendung bereitstellen.
  • Erhöhen Sie in bestimmten Fällen die Leistung, insbesondere in rechenintensiven Fällen wie Spielen.

So funktionierts

In diesem Abschnitt werden die Hauptkomponenten vorgestellt, die beim Erstellen einer nativen App für Android verwendet werden, und der Prozess der Erstellung und Paketerstellung beschrieben.

Hauptkomponenten

Sie sollten beim Erstellen Ihrer Anwendung mit den folgenden Komponenten vertraut sein:

  • Native gemeinsam genutzte Bibliotheken: Der NDK erstellt diese Bibliotheken bzw. .so-Dateien aus deinem C/C++-Quellcode.

  • Native statische Bibliotheken: Der NDK kann auch statische Bibliotheken oder .a-Dateien erstellen, die Sie mit anderen Bibliotheken verknüpfen können.

  • Java Native Interface (JNI): Die JNI ist die Schnittstelle, über die die Java- und C++-Komponenten miteinander kommunizieren. In diesem Leitfaden werden Kenntnisse der JNI vorausgesetzt. Informationen hierzu finden Sie in der Java Native Interface Specification.

  • Application Binary Interface (ABI): Die ABI definiert genau, wie der Maschinencode Ihrer Anwendung während der Laufzeit mit dem System interagieren soll. Der NDK erstellt .so-Dateien anhand dieser Definitionen. Verschiedene ABIs entsprechen unterschiedlichen Architekturen: Der NDK umfasst ABI-Unterstützung für 32-Bit-ARM, AArch64, x86 und x86-64. Weitere Informationen findest du unter Android-ABIs.

  • Manifest: Wenn Sie eine App ohne Java-Komponente schreiben, müssen Sie die Klasse NativeActivity im Manifest deklarieren. Weitere Informationen finden Sie unter native_activity.h-Oberfläche verwenden.

Volumenstrom

Der allgemeine Ablauf zur Entwicklung einer nativen App für Android sieht so aus:

  1. Entwerfen Sie Ihre Anwendung und entscheiden Sie, welche Teile in Java und welche als nativer Code implementiert werden sollen.

  2. Ein Android-App-Projekt können Sie wie jedes andere Android-App-Projekt erstellen.

  3. Wenn Sie eine rein native App schreiben, deklarieren Sie die Klasse NativeActivity in AndroidManifest.xml. Weitere Informationen finden Sie unter Native Aktivitäten und Anwendungen.

  4. Erstellen Sie eine Android.mk-Datei, die die native Bibliothek beschreibt, einschließlich des Namens, der Flags, verknüpften Bibliotheken und der Quelldateien, die im „JNI“-Verzeichnis kompiliert werden sollen.

  5. Optional können Sie eine Application.mk-Datei erstellen, in der die Ziel-ABIs, die Toolchain, der Release-/Debug-Modus und der STL konfiguriert werden. Wenn Sie nicht angeben, werden die folgenden Standardwerte verwendet:

    • ABI: alle nicht eingestellten ABIs
    • Modus: Veröffentlichung
    • STL: System
  6. Platzieren Sie Ihre native Quelle im Verzeichnis jni des Projekts.

  7. Verwenden Sie „ndk-build“, um die nativen Bibliotheken (.so, .a) zu kompilieren.

  8. Erstellen Sie die Java-Komponente und generieren Sie die ausführbare Datei .dex.

  9. Verpacken Sie alles in einer APK-Datei, die .so, .dex und andere Dateien enthält, die für die Ausführung Ihrer App erforderlich sind.

Native Aktivitäten und Anwendungen

Das Android SDK bietet die Hilfsklasse NativeActivity, mit der Sie eine vollständig native Aktivität schreiben können. NativeActivity verwaltet die Kommunikation zwischen dem Android-Framework und Ihrem nativen Code, sodass Sie keine Unterklassen erstellen oder seine Methoden aufrufen müssen. Sie müssen lediglich in der Datei AndroidManifest.xml die Anwendung als nativ deklarieren und mit der Erstellung der nativen Anwendung beginnen.

Eine Android-App, die NativeActivity verwendet, wird weiterhin auf ihrer eigenen virtuellen Maschine ausgeführt, die von anderen Anwendungen in einer Sandbox ausgeführt wird. Sie können daher weiterhin über die JNI auf Android Framework APIs zugreifen. In bestimmten Fällen, z. B. für Sensoren, Eingabeereignisse und Assets, bietet der NDK native Schnittstellen, die Sie verwenden können, anstatt über die JNI aufgerufen zu werden. Weitere Informationen zu einer solchen Unterstützung finden Sie unter Native APIs.

Unabhängig davon, ob Sie eine native Aktivität entwickeln oder nicht, empfehlen wir, Ihre Projekte mit den herkömmlichen Android-Build-Tools zu erstellen. Dies trägt dazu bei, dass Android-Apps mit der richtigen Struktur erstellt und verpackt werden können.

Das Android NDK bietet Ihnen zwei Möglichkeiten zur Implementierung Ihrer nativen Aktivität:

  • Der Header native_activity.h definiert die native Version der NativeActivity-Klasse. Sie enthält die Callback-Schnittstelle und die Datenstrukturen, die Sie zum Erstellen Ihrer nativen Aktivität benötigen. Da der Hauptthread Ihrer Anwendung die Callbacks verarbeitet, dürfen Ihre Callback-Implementierungen nicht blockiert werden. Wenn sie blockieren, erhalten Sie möglicherweise ANR-Fehler (Application Not Responding), da Ihr Hauptthread nicht reagiert, bis der Callback zurückgegeben wird.
  • Die Datei android_native_app_glue.h definiert eine statische Hilfsbibliothek, die auf der Schnittstelle native_activity.h basiert. Sie erzeugt einen weiteren Thread, der Dinge wie Callbacks oder Eingabeereignisse in einer Ereignisschleife verarbeitet. Wenn Sie diese Ereignisse in einen separaten Thread verschieben, verhindern Callbacks, dass Ihr Hauptthread blockiert wird.

Außerdem ist die Quelle <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c verfügbar, sodass Sie die Implementierung ändern können.

Weitere Informationen zur Verwendung dieser statischen Bibliothek finden Sie in der Beispielanwendung für native Aktivitäten und in der Dokumentation. Weitere Informationen finden Sie auch in den Kommentaren in der Datei <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h.

Native_activity.h-Oberfläche verwenden

So implementieren Sie eine native Aktivität mit der Schnittstelle native_activity.h:

  1. Erstellen Sie im Stammverzeichnis Ihres Projekts ein jni/-Verzeichnis. In diesem Verzeichnis wird Ihr gesamter nativer Code gespeichert.

  2. Deklarieren Sie Ihre native Aktivität in der Datei „AndroidManifest.xml“.

    Da Ihre Anwendung keinen Java-Code enthält, setzen Sie android:hasCode auf false.

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

    Sie müssen das Attribut android:name des Aktivitäts-Tags auf NativeActivity festlegen.

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

    Das Attribut android:value des meta-data-Tags gibt den Namen der gemeinsam genutzten Bibliothek an, die den Einstiegspunkt für die Anwendung enthält (z. B. C/C++ main), wobei das Präfix lib und das Suffix .so im Bibliotheksnamen weggelassen werden.

    <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. Erstellen Sie eine Datei für Ihre native Aktivität und implementieren Sie die Funktion, die in der Variablen ANativeActivity_onCreate angegeben ist. Die Anwendung ruft diese Funktion auf, wenn die native Aktivität beginnt. Diese Funktion empfängt, analog zu main in C/C++, einen Zeiger auf eine ANativeActivity-Struktur, die Funktionsverweise auf die verschiedenen Callback-Implementierungen enthält, die geschrieben werden müssen. Legen Sie die entsprechenden Callback-Funktionszeiger in ANativeActivity->callbacks auf die Implementierungen Ihrer Callbacks fest.

  4. Geben Sie im Feld ANativeActivity->instance die Adresse einer beliebigen Instanz bestimmter Daten an, die Sie verwenden möchten.

  5. Implementieren Sie alles andere, was Ihre Aktivität zu Beginn ausführen soll.

  6. Implementiere die restlichen Callbacks, die du in ANativeActivity->callbacks festgelegt hast. Weitere Informationen dazu, wann die Callbacks aufgerufen werden, finden Sie unter Aktivitätslebenszyklus verwalten.

  7. Entwickeln Sie den Rest Ihrer Anwendung.

  8. Erstellen Sie im Verzeichnis jni/ Ihres Projekts ein Android.mk file, um das native Modul für das Build-System zu beschreiben. Weitere Informationen findest du unter Android.mk.

  9. Sobald Sie eine Android.mk-Datei haben, kompilieren Sie Ihren nativen Code mit dem Befehl ndk-build.

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. Erstellen und installieren Sie Ihr Android-Projekt wie gewohnt. Befindet sich der native Code im Verzeichnis jni/, verpackt das Build-Script die daraus erstellten .so-Dateien automatisch im APK.

Zusätzlicher Beispielcode

Informationen zum Herunterladen von NDK-Beispielen finden Sie unter NDK-Beispiele.