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 (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.
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.
| Komponente | Zweck |
|---|---|
| Clang | C/C++-Compiler mit C++20-Unterstützung |
| libc++ | Standard-C++-Bibliothek (einzige in NDK r27) |
| CMake | Build-System für native Bibliotheken |
| LLDB | Nativer Code-Debugger in Android Studio |
| ndk-build | Veraltetes Build-System (durch CMake ersetzt) |
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.
| Kriterium | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Leistung | Mittel (JIT/AOT-Kompilierung) | Hoch (Maschinencode) |
| Audio-Latenz | 50–200 ms | 5–15 ms über Oboe |
| 3D-Grafik | Über Canvas/OpenGL Kotlin API | Vulkan/OpenGL direkt |
| Entwicklungskomplexität | Niedrig | Hoch (Speicherverwaltung, JNI) |
| Code-Portabilität | Nur Android | Linux, Windows, macOS, iOS |
| APK-Größe | Minimal | +1–10 MB pro Bibliothek |
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/
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
Ü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 (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.
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++"
#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;
}
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.
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)
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 (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.
#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");
}
| ABI | Architektur | Bitbreite | Geräte |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-Bit | Fast alle modernen Smartphones |
| armeabi-v7a | ARMv7-A | 32-Bit | Ältere Geräte (vor 2020) |
| x86_64 | x86-64 | 64-Bit | Emulator, Chromebook |
| x86 | x86 IA-32 | 32-Bit | Veraltete Emulatoren |
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.
#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;
}
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.
#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
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.
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.
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.
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.
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
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.
Lesen Sie auch