NDK Android: Was es ist, Native Development Kit und JNI für C++

Autor: IT Sectr Veröffentlicht: 2026-02-09 Lesezeit: 10 Min.

NDK (Native Development Kit) ist ein Toolkit zum Schreiben von Teilen einer Anwendung in C und C++ für Android. Im Gegensatz zum üblichen Android SDK kompiliert NDK Code in native Bibliotheken (.so), die direkt mit dem Prozessor arbeiten, ohne eine virtuelle Maschinenebene. Laut Google NDK Guides, 2026 wird NDK für Hochleistungsrechnen, Spiele, Audioverarbeitung und die Wiederverwendung vorhandener C/C++-Projekte verwendet. JNI (Java Native Interface) verbindet nativen Code mit Kotlin und Java.

Wichtigste Erkenntnisse

  • NDK — ein Toolkit zum Kompilieren von C/C++-Code in native Bibliotheken für Android.
  • JNI — eine Schnittstelle für die Interaktion zwischen der Java/Kotlin-VM und nativem Code.
  • CMake — das primäre Build-System für NDK-Projekte, konfigurierbar über CMakeLists.txt.
  • ABI — die Zielprozessorarchitektur (arm64-v8a, armeabi-v7a, x86_64), für die die Bibliothek erstellt wird.
  • NDK wird für die meisten Android-Apps nicht benötigt und kommt nur bei Aufgaben mit hohen Leistungsanforderungen zum Einsatz.

Was ist NDK

NDK (Native Development Kit) ist eine Sammlung von Werkzeugen zur Cross-Kompilierung von C- und C++-Code in ausführbare Bibliotheken für Android. Zum NDK gehören der Clang-Compiler, die libc++-Standardbibliothek, Android-API-Header-Dateien und Build-Dienstprogramme. Der Entwickler schreibt nativen Code in C oder C++, kompiliert ihn in .so-Dateien (Shared Objects) und bindet sie über JNI in die Anwendung ein.

NDK ersetzt nicht das Android SDK, sondern ergänzt es. Die gesamte Benutzeroberfläche, der Lebenszyklus und die Systemdienste bleiben in Kotlin oder Java. Nativer Code löst spezifische Aufgaben: mathematische Berechnungen, Kryptografie, Codecs, Physik in Spielen. Google empfiehlt, NDK nur zu verwenden, wenn das SDK nicht die erforderliche Leistung oder den Zugriff auf Hardwarefunktionen bietet.

Die Geschichte von NDK beginnt im Jahr 2009 (NDK r1). Seitdem hat sich das Toolkit von einer experimentellen Skriptsammlung zu einem ausgereiften System mit Unterstützung für CMake, LLDB-Debugging und Profilierung entwickelt. Im Jahr 2026 ist die aktuelle Version NDK r27 mit Clang 19, vollständiger C++20-Unterstützung und libc++ als einziger Standardbibliothek.

Wichtige NDK-Funktionen

NDK bietet dem Entwickler Zugriff auf die Low-Level-Funktionen von Android über native APIs. Die wichtigsten Anwendungsfälle sind: Arbeiten mit OpenGL ES und Vulkan für 3D-Grafiken, Audioverarbeitung über Oboe, kryptografische Operationen über BoringSSL und NEON-Optimierungen für ARM. Alle diese APIs sind von C/C++ aus verfügbar und erfordern NDK zur Kompilierung.

Darüber hinaus ermöglicht NDK die Wiederverwendung vorhandener C/C++-Bibliotheken, ohne sie in Kotlin neu schreiben zu müssen. Dies ist besonders relevant für Projekte mit einer langen Geschichte in C++ — Spiele-Engines (Unity, Unreal Engine), Computer-Vision-Bibliotheken (OpenCV) oder kryptografische Pakete (OpenSSL). In solchen Fällen spart NDK Jahre an Entwicklungszeit.

KomponenteZweck
ClangC/C++-Compiler mit C++20-Unterstützung
libc++Standard-C++-Bibliothek (einzige in NDK r27)
CMakeBuild-System für native Bibliotheken
LLDBNativer Code-Debugger in Android Studio
ndk-buildVeraltetes Build-System (durch CMake ersetzt)

NDK vs SDK: Wann nativer Code benötigt wird

Die Wahl zwischen NDK und reinem SDK hängt von der Aufgabe ab. Das Android SDK bietet fertige Java/Kotlin-APIs für 90% der Szenarien — Netzwerk, Dateien, Benachrichtigungen, Kamera. NDK wird verwendet, wenn diese APIs nicht die erforderliche Leistung oder Funktionalität bieten. Beispielsweise ist Echtzeit-Audioverarbeitung über SDK möglich, jedoch mit einer Latenz von 50–200 ms, während eine native Bibliothek über Oboe die Latenz auf 5–15 ms reduziert.

Die APK-Größe ist ein weiterer Faktor. Das Hinzufügen von NDK vergrößert die Anwendung, da jede ABI-Architektur eine separate .so-Bibliothek erfordert. Die Verwendung von Android App Bundle (AAB) mildert das Problem jedoch: Google Play liefert dem Benutzer nur die Bibliothek für seine Architektur. Ein typisches natives Projekt fügt 1–10 MB zur Installationsgröße pro Gerät hinzu.

SDK vs NDK Vergleich nach Kriterien

KriteriumSDK (Kotlin/Java)NDK (C/C++)
LeistungMittel (JIT/AOT-Kompilierung)Hoch (Maschinencode)
Audio-Latenz50–200 ms5–15 ms über Oboe
3D-GrafikÜber Canvas/OpenGL Kotlin APIVulkan/OpenGL direkt
EntwicklungskomplexitätNiedrigHoch (Speicherverwaltung, JNI)
Code-PortabilitätNur AndroidLinux, Windows, macOS, iOS
APK-GrößeMinimal+1–10 MB pro Bibliothek

NDK-Architektur: Werkzeuge und Bibliotheken

NDK wird getrennt vom Android SDK über den SDK Manager installiert. Im NDK-Verzeichnis befinden sich die Toolchain (Compiler), Plattformbibliotheken, Header-Dateien und Dienstprogramme. Die NDK-Toolchain enthält Clang für die Cross-Kompilierung für alle Ziel-ABIs: arm64-v8a, armeabi-v7a, x86_64 und x86. Der Compiler wählt automatisch die erforderliche Architektur basierend auf CMake- oder ndk-build-Flags aus.

Android-APIs für nativen Code werden durch Header-Dateien im Verzeichnis sysroot/usr/include bereitgestellt. Dort befinden sich Deklarationen für alle in nativem Code verfügbaren APIs: native_activity.h für den Activity-Lebenszyklus, input.h für Eingabeereignisse, sensor.h für Sensoren. Die Einbindung dieser Header ermöglicht den Zugriff auf Hardwarefunktionen ohne JNI-Ebene.

NDK-Verzeichnisstruktur

text
ndk/
  toolchains/
    llvm/prebuilt/windows-x86_64/
      bin/        // Clang, ld, llvm-profdata
      sysroot/    // Android-API-Header-Dateien
  platforms/
    android-26/  // libc, libm, libdl für API 26
    android-34/
  sources/
    cxx-stl/     // libc++-Header
  build/
    cmake/       // CMake-Toolchain-Datei

Native Android-APIs

Über NDK sind die folgenden Gruppen nativer APIs verfügbar: Native App Glue(Verwaltung des Activity-Lebenszyklus von C aus), OpenGL ES 3.2 und Vulkan 1.3 (Grafik), Oboe(Audio mit geringer Latenz), Neural Networks API (maschinelles Lernen auf dem Gerät). Jede API verfügt über eine Header-Datei und eine statische/dynamische Bibliothek als Teil von NDK.

Die Arbeit mit nativen APIs erfordert kein JNI — Funktionen werden direkt von C/C++-Code aus aufgerufen. Für die Interaktion mit der Kotlin-Benutzeroberfläche ist jedoch weiterhin JNI erforderlich. Diese hybride Architektur ist in Spiele-Engines üblich: Grafik und Physik in C++ (über Vulkan), Menüs und UI in Kotlin (über Jetpack Compose).

JNI: Wie Kotlin C++ aufruft

JNI (Java Native Interface) ist ein Standardmechanismus zum Aufrufen von nativem Code aus der Java/Kotlin-VM. Der Entwickler deklariert eine externe Funktion in Kotlin mit dem Schlüsselwort external und lädt die .so-Bibliothek über System.loadLibrary. Auf der C++-Seite wird die Funktion unter Verwendung der JNI-Namenskonvention deklariert, die den Paket- und Klassennamen codiert.

Deklaration einer nativen Funktion in Kotlin

kotlin
class NativeBridge {
    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }

    external fun stringFromJNI(): String
    external fun fibonacci(n: Int): Long
    external fun processBuffer(data: ByteArray): ByteArray
}

// Verwendung im Code
val bridge = NativeBridge()
println(bridge.stringFromJNI())  // "Hello from C++"

JNI-Funktionsimplementierung in C++

cpp
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_NativeBridge_stringFromJNI(
    JNIEnv* env, jobject /* this */) {
    std::string hello = "Hello from C++ NDK";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jlong JNICALL
Java_com_example_app_NativeBridge_fibonacci(
    JNIEnv* env, jobject /* this */, jint n) {
    if (n <= 1) return n;
    jlong a = 0, b = 1;
    for (int i = 2; i <= n; i++) {
        jlong temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

CMakeLists.txt für NDK einrichten

CMake ist das primäre Build-System für NDK, das das veraltete ndk-build abgelöst hat. Die Datei CMakeLists.txt beschreibt Quelldateien, Bibliotheken und Kompilierungsflags. Android Studio ruft CMake automatisch beim Erstellen des Projekts auf, wenn externalNativeBuild in build.gradle konfiguriert ist. CMake generiert Makefiles für jedes Ziel-ABI und kompiliert nativen Code parallel.

Beispiel CMakeLists.txt für eine native Bibliothek

cmake
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")

# Header-Dateien einbinden
include_directories(src/main/cpp/include)

# Native Bibliothek erstellen
add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
    src/main/cpp/math_utils.cpp
    src/main/cpp/audio_processor.cpp
)

# Android-Systembibliotheken verlinken
target_link_libraries(
    native-lib
    android
    log
    OpenSLES
    # libc++ wird automatisch verlinkt
)

# Optimierungsflags
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)

build.gradle für NDK konfigurieren

groovy
android {
    defaultConfig {
        ndk {
            // Ziel-ABIs für den Build
            abiFilters "arm64-v8a", "armeabi-v7a", "x86_64"
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
            version "3.22.1"
        }
    }
    buildTypes {
        release {
            externalNativeBuild {
                cmake {
                    arguments "-DCMAKE_BUILD_TYPE=Release"
                }
            }
        }
    }
}

ABI und plattformübergreifender Build

ABI (Application Binary Interface) ist das Maschinencode-Format, das die Kompatibilität mit dem Prozessor des Geräts bestimmt. Jede ARM- oder x86-Architektur hat ihr eigenes ABI. NDK kompiliert nativen Code separat für jedes angegebene ABI. Die häufigsten ABIs im Jahr 2026: arm64-v8a (99% der modernen Geräte), armeabi-v7a (ältere 32-Bit-Geräte), x86_64 (Emulator und Chromebook).

Die Angabe von abiFilters in build.gradle beschränkt den Build auf die erforderlichen Architekturen und verkürzt die Kompilierungszeit. Für Google Play wird empfohlen, alle ABIs einzubeziehen, die die Bibliothek unterstützt — dies gewährleistet die Funktion auf allen Geräten. Die Google Play Console ermöglicht die Konfiguration ABI-spezifischer APK-Auslieferung über App Bundle.

Ermittlung der Geräte-ABI in nativem Code

cpp
#include <jni.h>
#include <android/api-level.h>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_NativeBridge_getABIInfo(
    JNIEnv* env, jobject /* this */) {

    #if defined(__arm__)
        #if defined(__ARM_ARCH_7A__)
            return env->NewStringUTF("armeabi-v7a");
        #endif
    #elif defined(__aarch64__)
        return env->NewStringUTF("arm64-v8a");
    #elif defined(__x86_64__)
        return env->NewStringUTF("x86_64");
    #elif defined(__i386__)
        return env->NewStringUTF("x86");
    #endif

    return env->NewStringUTF("unknown");
}
ABIArchitekturBitbreiteGeräte
arm64-v8aARMv8-A64-BitFast alle modernen Smartphones
armeabi-v7aARMv7-A32-BitÄltere Geräte (vor 2020)
x86_64x86-6464-BitEmulator, Chromebook
x86x86 IA-3232-BitVeraltete Emulatoren

Beispiele für nativen C++-Code

Betrachten wir ein praktisches Beispiel: eine mathematische Bibliothek für die Arbeit mit Gleitkommazahlen. Nativer C++-Code führt Berechnungen dank direktem Zugriff auf ARM-NEON-Instruktionen und dem Fehlen von Array-Grenzprüfungen zur Laufzeit effizienter aus als Kotlin. Dieses Beispiel zeigt ein typisches NDK-Nutzungsmuster — die Auslagerung schwerer Berechnungen in die native Ebene.

Mathematische Operationen in nativem Code

cpp
#include <jni.h>
#include <cmath>
#include <vector>

extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_example_app_NativeBridge_normalizeArray(
    JNIEnv* env, jobject, jfloatArray input) {

    jsize len = env->GetArrayLength(input);
    jfloat* elements = env->GetFloatArrayElements(input, nullptr);

    // Mittelwert und Standardabweichung berechnen
    float sum = 0.0f, sumSq = 0.0f;
    for (jsize i = 0; i < len; i++) {
        sum += elements[i];
        sumSq += elements[i] * elements[i];
    }
    float mean = sum / len;
    float stddev = std::sqrt(sumSq / len - mean * mean);

    // Normalisierung: (x - mean) / stddev
    jfloat* result = new jfloat[len];
    for (jsize i = 0; i < len; i++) {
        result[i] = (elements[i] - mean) / stddev;
    }

    env->ReleaseFloatArrayElements(input, elements, JNI_ABORT);
    jfloatArray output = env->NewFloatArray(len);
    env->SetFloatArrayRegion(output, 0, len, result);
    delete[] result;
    return output;
}

Protokollierung aus nativem Code

Verwenden Sie zum Debuggen von nativem Code das Makro __android_log_print aus der Bibliothek android/log.h. Nachrichten erscheinen in Logcat neben Java/Kotlin-Logs. Die Protokollebene (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) hilft beim Filtern von Nachrichten.

cpp
#include <android/log.h>
#define LOG_TAG "NativeLib"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

extern "C" JNIEXPORT void JNICALL
Java_com_example_app_NativeBridge_processData(
    JNIEnv* env, jobject, jint count) {

    LOGD("Processing %d items", count);

    for (int i = 0; i < count; i++) {
        // Schwere Verarbeitung
        LOGD("Item %d processed", i);
    }

    LOGD("Processing complete");
}

Häufig gestellte Fragen

Ist NDK für die Android-Entwicklung obligatorisch?

Nein. Für die meisten Anwendungen reicht das Kotlin-SDK aus. NDK wird benötigt für Hochleistungsaufgaben: Echtzeit-Audio-/Video-Verarbeitung, 3D-Grafik, Kryptografie oder Wiederverwendung vorhandener C/C++-Projekte.

Welchen Compiler verwendet NDK?

NDK verwendet Clang aus der LLVM-Toolchain. Seit NDK r23 wurde GCC vollständig entfernt. Clang cross-kompiliert Code für alle Android-ABIs: arm64-v8a, armeabi-v7a, x86_64, x86.

Was ist ABI im Kontext von NDK?

ABI (Application Binary Interface) ist das Maschinencode-Format, das die Kompatibilität mit dem Prozessor bestimmt. NDK erstellt .so-Bibliotheken für jedes ABI separat. arm64-v8a ist das primäre ABI für moderne Android-Geräte.

Kann C++-Code über NDK debuggert werden?

Ja. Android Studio unterstützt LLDB — einen Debugger für nativen Code. Sie können Breakpoints in C++-Dateien setzen, Variablen und den Aufrufstapel anzeigen. NDK und das LLDB-Plugin sind erforderlich.

Wie wirkt sich NDK auf die APK-Größe aus?

Jede native Bibliothek fügt 100 KB bis mehrere MB zur APK hinzu. Jedes ABI erfordert eine separate .so-Bibliothek. Android App Bundle liefert dem Benutzer nur die passende Architektur und reduziert so die Installationsgröße.

Zusammenfassung

  • NDK — eine Sammlung von Werkzeugen zur Cross-Kompilierung von C/C++-Code in native Android-Bibliotheken mit dem Clang-Compiler.
  • JNI — eine Schnittstelle, die Kotlin/Java über das Schlüsselwort external und Funktionsnamenskonventionen mit nativem Code verbindet.
  • CMake — das primäre NDK-Build-System, konfiguriert über CMakeLists.txt und externalNativeBuild in Gradle.
  • ABI definiert die Prozessorarchitektur — arm64-v8a, armeabi-v7a, x86_64. Jedes ABI erfordert einen separaten Bibliotheks-Build.
  • Verwenden Sie NDK nur für Aufgaben, die hohe Leistung erfordern: Spiele, Audio, Grafik, Kryptografie, maschinelles Lernen auf dem Gerät.
  • Google Play unterstützt ABI-Aufteilung über App Bundle: Der Benutzer erhält nur die Bibliothek für die Architektur seines Geräts.
  • Native Bibliotheken erhöhen die APK-Größe erheblich, bieten aber maximale Leistung und geringe Latenz für kritische Vorgänge.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch