NDK (Native Development Kit) — is een toolkit voor het schrijven van een deel van de app in C en C++ voor Android. In tegenstelling tot de gewone Android SDK, compileert NDK code naar native bibliotheken (.so) die direct op de processor werken zonder virtuele machine-laag. Volgens Google NDK Guides, 2026, wordt NDK gebruikt voor krachtige berekeningen, games, audioverwerking en hergebruik van bestaande C/C++ projecten. JNI (Java Native Interface) verbindt native code met Kotlin en Java.
Belangrijkste punten
NDK (Native Development Kit) — is een set tools voor het cross-compileren van C en C++ code naar uitvoerbare bibliotheken voor Android. NDK bevat de Clang compiler, de libc++ standaardbibliotheek, Android API headerbestanden en build-hulpprogramma's. De ontwikkelaar schrijft native code in C of C++, compileert deze naar .so-bestanden (shared objects) en koppelt deze via JNI aan de app.
NDK vervangt Android SDK niet, maar vult het aan. De hele UI, lifecycle en systeemdiensten blijven in Kotlin of Java. Native code lost specifieke taken op: wiskundige berekeningen, cryptografie, codecs, fysica in games. Google adviseert NDK alleen te gebruiken wanneer SDK niet de vereiste prestaties of toegang tot hardwaremogelijkheden biedt.
De geschiedenis van NDK begint in 2009 (NDK r1). In die tijd zijn de tools geëvolueerd van een experimentele set scripts tot een volwassen systeem met ondersteuning voor CMake, LLDB-debugging en profilering. In 2026 is de huidige versie NDK r27 met Clang 19, volledige ondersteuning voor C++20 en libc++ als enige standaardbibliotheek.
NDK geeft de ontwikkelaar toegang tot low-level mogelijkheden van Android via native API's. De belangrijkste gebruiksscenario's omvatten: werken met OpenGL ES en Vulkan voor 3D-graphics, audioverwerking via Oboe, cryptografische operaties via BoringSSL en NEON-optimalisaties voor ARM. Al deze API's zijn toegankelijk vanuit C/C++ en vereisen NDK voor compilatie.
Daarnaast maakt NDK het mogelijk bestaande C/C++ bibliotheken te hergebruiken zonder ze naar Kotlin te herschrijven. Dit is vooral relevant voor projecten met een jarenlange geschiedenis in C++ — game-engines (Unity, Unreal Engine), computer vision bibliotheken (OpenCV) of cryptografische pakketten (OpenSSL). In zulke gevallen bespaart NDK jaren aan ontwikkelingstijd.
| Component | Doel |
|---|---|
| Clang | C/C++ compiler met C++20 ondersteuning |
| libc++ | Standaard C++ bibliotheek (enige in NDK r27) |
| CMake | Buildsysteem voor native bibliotheken |
| LLDB | Native code debugger in Android Studio |
| ndk-build | Verouderd buildsysteem (vervangen door CMake) |
De keuze tussen NDK en pure SDK hangt af van de taak. Android SDK bied kant-en-klare Java/Kotlin API's voor 90% van de scenario's — werken met netwerk, bestanden, meldingen, camera. NDK wordt aangesloten wanneer deze API's niet de vereiste prestaties of functionaliteit bieden. Bijvoorbeeld, real-time audioverwerking via SDK is mogelijk, maar met vertragingen van 50–200 ms, terwijl een native bibliotheek via Oboe de vertraging reduceert tot 5–15 ms.
APK-grootte — een andere factor. Toevoeging van NDK vergroot de app-grootte, omdat elke ABI-architectuur een aparte .so-bibliotheek vereist. Het gebruik van Android App Bundle (AAB) verzacht het probleem echter: Google Play levert de gebruiker alleen de bibliotheek voor zijn architectuur. Een typisch native project voegt 1–10 MB toe aan de installatiegrootte op het apparaat.
| Criterium | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Prestaties | Gemiddeld (JIT/AOT compilatie) | Hoog (machinecode) |
| Audiovertraging | 50–200 ms | 5–15 ms via Oboe |
| 3D-graphics | Via Canvas/OpenGL Kotlin API | Direct Vulkan/OpenGL |
| Ontwikkelingscomplexiteit | Laag | Hoog (geheugenbeheer, JNI) |
| Code-portabiliteit | Alleen Android | Linux, Windows, macOS, iOS |
| APK-grootte | Minimaal | +1–10 MB per bibliotheek |
NDK wordt apart van Android SDK geïnstalleerd via SDK Manager. Binnen de NDK-directory bevinden zich toolchain (compilers), platformbibliotheken, headerbestanden en hulpprogramma's. NDK Toolchain bevat Clang voor cross-compilatie voor alle doel-ABI's: arm64-v8a, armeabi-v7a, x86_64 en x86. De compiler selecteert automatisch de juiste architectuur op basis van CMake of ndk-build flags.
Android API's voor native code worden vertegenwoordigd door headerbestanden in de directory sysroot/usr/include. Daar bevinden zich declaraties voor alle API's die beschikbaar zijn in native code: native_activity.h voor Activity lifecycle, input.h voor invoergebeurtenissen, sensor.h voor sensoren. Het koppelen van deze headers geeft toegang tot hardwaremogelijkheden zonder JNI-laag.
ndk/
toolchains/
llvm/prebuilt/windows-x86_64/
bin/ // Clang, ld, llvm-profdata
sysroot/ // Android API headerbestanden
platforms/
android-26/ // libc, libm, libdl voor API 26
android-34/
sources/
cxx-stl/ // libc++ headers
build/
cmake/ // CMake toolchain bestand
Via NDK zijn de volgende groepen native API's beschikbaar: Native App Glue (beheer van Activity lifecycle vanuit C), OpenGL ES 3.2 en Vulkan 1.3 (graphics), Oboe (audio met lage latentie), Neural Networks API (machine learning op het apparaat). Elke API heeft een headerbestand en een statische/dynamische bibliotheek in NDK.
Voor het werken met native API's is geen JNI nodig — functies worden direct vanuit C/C++ code aangeroepen. Voor interactie met de UI in Kotlin is echter nog steeds JNI vereist. Deze hybride architectuur komt voor in game-engines: graphics en fysica in C++ (via Vulkan), menu en UI in Kotlin (via Jetpack Compose).
JNI (Java Native Interface) — het standaardmechanisme voor het aanroepen van native code vanuit de Java/Kotlin virtuele machine. De ontwikkelaar declareert in Kotlin een externe functie met het sleutelwoord external en koppelt de .so-bibliotheek via System.loadLibrary. Aan de C++-kant wordt de functie gedeclareerd met de JNI-naamgevingsconventie die het pakket en de klassenaam codeert.
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
}
// Gebruik in 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 — het primaire buildsysteem voor NDK, dat de verouderde ndk-build heeft vervangen. Het bestand CMakeLists.txt beschrijft de bronbestanden, bibliotheken en compilatievlaggen. Android Studio roept automatisch CMake aan bij het bouwen van het project als externalNativeBuild is geconfigureerd in build.gradle. CMake genereert make-bestanden voor elke doel-ABI en compileert native code parallel.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# Headerbestanden koppelen
include_directories(src/main/cpp/include)
# Native bibliotheek maken
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# Android systeembibliotheken koppelen
target_link_libraries(
native-lib
android
log
OpenSLES
# libc++ wordt automatisch gekoppeld
)
# Optimalisatievlaggen
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)
android {
defaultConfig {
ndk {
// Doel-ABI's voor 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) — is het formaat van machinecode dat de compatibiliteit met de processor van het apparaat bepaalt. Elke ARM- of x86-architectuur heeft zijn eigen ABI. NDK compileert native code apart voor elke opgegeven ABI. De meest voorkomende ABI's in 2026: arm64-v8a (99% van moderne apparaten), armeabi-v7a (oude 32-bit apparaten), x86_64 (emulator en Chromebook).
Het specificeren van abiFilters in build.gradle beperkt de build tot alleen de benodigde architecturen, wat de compilatietijd verkort. Voor Google Play wordt aanbevolen alle ABI's op te nemen waarmee de bibliotheek compatibel is — dit garandeert werking op alle apparaten. Google Play Console maakt het mogelijk ABI-specifieke APK-levering via App Bundle te configureren.
#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 | Architectuur | Bitgrootte | Apparaten |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-bit | Bijna alle moderne telefoons |
| armeabi-v7a | ARMv7-A | 32-bit | Oude apparaten (tot 2020) |
| x86_64 | x86-64 | 64-bit | Emulator, Chromebook |
| x86 | x86 IA-32 | 32-bit | Verouderde emulators |
Laten we een praktisch voorbeeld bekijken: een wiskundige bibliotheek voor het werken met getallen met drijvende komma. Native code in C++ voert berekeningen efficiënter uit dan Kotlin, dankzij directe toegang tot NEON ARM-instructies en het ontbreken van array-grenscontroles in runtime. Dit voorbeeld toont het typische patroon van NDK-gebruik — het verplaatsen van zware berekeningen naar de native laag.
#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);
// Gemiddelde en standaarddeviatie berekenen
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);
// Normalisatie: (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;
}
Gebruik voor het debuggen van native code de macro __android_log_print uit de bibliotheek android/log.h. Berichten verschijnen in Logcat naast Java/Kotlin logs. Het logniveau (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) helpt bij het filteren van berichten.
#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++) {
// Zware verwerking
LOGD("Item %d processed", i);
}
LOGD("Processing complete");
}
Veelgestelde vragen
Nee. Voor de meeste apps is SDK in Kotlin voldoende. NDK is nodig voor taken met hoge prestaties: real-time audio/video verwerking, 3D-graphics, cryptografie of hergebruik van bestaande C/C++ projecten.
NDK gebruikt Clang uit de LLVM toolchain. Sinds NDK r23 is GCC volledig verwijderd. Clang cross-compileert code voor alle Android ABI's: arm64-v8a, armeabi-v7a, x86_64, x86.
ABI (Application Binary Interface) — het formaat van machinecode dat de compatibiliteit met de processor bepaalt. NDK bouwt .so-bibliotheken voor elke ABI apart. arm64-v8a — de belangrijkste ABI voor moderne Android-apparaten.
Ja. Android Studio ondersteunt LLDB — de native code debugger. Je kunt breakpoints plaatsen in C++ bestanden, variabelen en de call-stack bekijken. Voor gebruik zijn NDK en de LLDB-plugin vereist.
Elke native bibliotheek voegt 100 KB — enkele MB's toe aan de APK. Voor elke ABI is een aparte .so-bibliotheek nodig. Android App Bundle levert de gebruiker alleen de juiste architectuur, waardoor de installatiegrootte afneemt.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook