NDK (Native Development Kit) — är en verktygssats för att skriva delar av applikationen i C och C++ för Android. Till skillnad från vanliga Android SDK kompilerar NDK kod till inbyggda bibliotek (.so) som arbetar direkt på processorn utan ett virtuellt maskinlager. Enligt Google NDK Guides, 2026, används NDK för högpresterande beräkningar, spel, ljudbearbetning och återanvändning av befintliga C/C++-projekt. JNI (Java Native Interface) kopplar samman inbyggd kod med Kotlin och Java.
Huvudpunkter
NDK (Native Development Kit) — är en uppsättning verktyg för att korskompilera C och C++-kod till körbara bibliotek för Android. NDK innehåller Clang-kompilatorn, libc++ standardbibliotek, Android API-huvudfiler och byggverktyg. Utvecklaren skriver inbyggd kod i C eller C++, kompilerar den till .so-filer (shared objects) och ansluter den till appen via JNI.
NDK ersätter inte Android SDK, utan kompletterar det. Hela UI, lifecycle och systemtjänster förblir i Kotlin eller Java. Inbyggd kod löser specifika uppgifter: matematiska beräkningar, kryptografi, codec, fysik i spel. Google rekommenderar att använda NDK endast när SDK inte ger den prestanda eller åtkomst till hårdvarufunktioner som krävs.
NDK:s historia börjar 2009 (NDK r1). Under denna tid har verktygen utvecklats från en experimentell uppsättning skript till ett moget system med stöd för CMake, LLDB-felsökning och profilering. Från och med 2026 är den aktuella versionen NDK r27 med Clang 19, fullt stöd för C++20 och libc++ som enda standardbibliotek.
NDK ger utvecklaren tillgång till lågnivåfunktioner i Android via inbyggda API:er. De huvudsakliga användningsscenarierna inkluderar: arbete med OpenGL ES och Vulkan för 3D-grafik, ljudbearbetning via Oboe, kryptografiska operationer via BoringSSL och NEON-optimeringar för ARM. Alla dessa API:er är tillgängliga från C/C++ och kräver NDK för kompilering.
Dessutom gör NDK det möjligt att återanvända befintliga C/C++-bibliotek utan att skriva om dem till Kotlin. Detta är särskilt relevant för projekt med lång historia i C++ — spelmotorer (Unity, Unreal Engine), datorseendebibliotek (OpenCV) eller kryptografiska paket (OpenSSL). I sådana fall sparar NDK år av utveckling.
| Komponent | Syfte |
|---|---|
| Clang | C/C++-kompilator med stöd för C++20 |
| libc++ | Standard C++-bibliotek (enda i NDK r27) |
| CMake | Byggsystem för inbyggda bibliotek |
| LLDB | Felsökare för inbyggd kod i Android Studio |
| ndk-build | Föråldrat byggsystem (ersatt av CMake) |
Valet mellan NDK och rent SDK beror på uppgiften. Android SDK tillhandahåller färdiga Java/Kotlin-API:er för 90% av scenarierna — arbete med nätverk, filer, notifikationer, kamera. NDK ansluts när dessa API:er inte ger den prestanda eller funktionalitet som krävs. Till exempel är realtidsljudbearbetning via SDK möjlig, men med fördröjningar på 50–200 ms, medan ett inbyggt bibliotek via Oboe minskar fördröjningen till 5–15 ms.
APK-storlek — ytterligare en faktor. Att lägga till NDK ökar appens storlek eftersom varje ABI-arkitektur kräver ett separat .so-bibliotek. Användning av Android App Bundle (AAB) mildrar dock problemet: Google Play levererar till användaren endast biblioteket för dess arkitektur. Ett typiskt inbyggt projekt lägger till 1–10 MB till installationsstorleken på enheten.
| Kriterium | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Prestanda | Medel (JIT/AOT-kompilering) | Hög (maskinkod) |
| Ljudfördröjning | 50–200 ms | 5–15 ms via Oboe |
| 3D-grafik | Via Canvas/OpenGL Kotlin API | Direkt Vulkan/OpenGL |
| Utvecklingskomplexitet | Låg | Hög (minneshantering, JNI) |
| Kodportabilitet | Endast Android | Linux, Windows, macOS, iOS |
| APK-storlek | Minimal | +1–10 MB per bibliotek |
NDK installeras separat från Android SDK via SDK Manager. Inuti NDK-katalogen finns toolchain (kompilatorer), plattformsbibliotek, huvudfiler och verktyg. NDK Toolchain innehåller Clang för korskompilering för alla mål-ABI:er: arm64-v8a, armeabi-v7a, x86_64 och x86. Kompilatorn väljer automatiskt rätt arkitektur baserat på CMake- eller ndk-build-flaggor.
Android API:er för inbyggd kod representeras av huvudfiler i katalogen sysroot/usr/include. Där finns deklarationer för alla API:er som är tillgängliga i inbyggd kod: native_activity.h för Activity lifecycle, input.h för inmatningshändelser, sensor.h för sensorer. Att ansluta dessa huvudfiler ger tillgång till hårdvarufunktioner utan JNI-lager.
ndk/
toolchains/
llvm/prebuilt/windows-x86_64/
bin/ // Clang, ld, llvm-profdata
sysroot/ // Android API-huvudfiler
platforms/
android-26/ // libc, libm, libdl för API 26
android-34/
sources/
cxx-stl/ // libc++-huvudfiler
build/
cmake/ // CMake toolchain-fil
Via NDK är följande grupper av inbyggda API:er tillgängliga: Native App Glue (hantering av Activity lifecycle från C), OpenGL ES 3.2 och Vulkan 1.3 (grafik), Oboe (ljud med låg latens), Neural Networks API (maskininlärning på enheten). Varje API har en huvudfil och ett statiskt/dynamiskt bibliotek i NDK-sammansättningen.
För att arbeta med inbyggda API:er behövs ingen JNI — funktioner anropas direkt från C/C++-kod. För interaktion med UI i Kotlin krävs dock fortfarande JNI. Denna hybridarkitektur förekommer i spelmotorer: grafik och fysik i C++ (via Vulkan), meny och UI i Kotlin (via Jetpack Compose).
JNI (Java Native Interface) — standardmekanismen för att anropa inbyggd kod från Java/Kotlin virtuell maskin. Utvecklaren deklarerar i Kotlin en extern funktion med nyckelordet external och ansluter .so-biblioteket via System.loadLibrary. På C++-sidan deklareras funktionen med JNI-namngivningskonventionen som kodar paket och klassnamn.
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
}
// Användning i kod
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 — det primära byggsystemet för NDK, som har ersatt det föråldrade ndk-build. Filen CMakeLists.txt beskriver källfiler, bibliotek och kompileringsflaggor. Android Studio anropar automatiskt CMake vid byggning av projektet om externalNativeBuild är konfigurerat i build.gradle. CMake genererar make-filer för varje mål-ABI och kompilerar inbyggd kod parallellt.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# Anslutning av huvudfiler
include_directories(src/main/cpp/include)
# Skapa inbyggt bibliotek
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# Anslutning av Android-systembibliotek
target_link_libraries(
native-lib
android
log
OpenSLES
# libc++ ansluts automatiskt
)
# Optimeringsflaggor
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)
android {
defaultConfig {
ndk {
// Mål-ABI:er för byggning
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) — är formatet på maskinkod som bestämmer kompatibilitet med enhetens processor. Varje ARM- eller x86-arkitektur har sitt eget ABI. NDK kompilerar inbyggd kod separat för varje angivet ABI. De vanligaste ABI:erna 2026: arm64-v8a (99% av moderna enheter), armeabi-v7a (gamla 32-bitars enheter), x86_64 (emulator och Chromebook).
Att ange abiFilters i build.gradle begränsar byggningen till endast nödvändiga arkitekturer, vilket minskar kompileringstiden. För Google Play rekommenderas att inkludera alla ABI:er som biblioteket är kompatibelt med — detta garanterar funktion på alla enheter. Google Play Console gör det möjligt att konfigurera ABI-specifik APK-leverans via 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 | Arkitektur | Bit | Enheter |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-bit | Nästan alla moderna telefoner |
| armeabi-v7a | ARMv7-A | 32-bit | Gamla enheter (före 2020) |
| x86_64 | x86-64 | 64-bit | Emulator, Chromebook |
| x86 | x86 IA-32 | 32-bit | Föråldrade emulatorer |
Låt oss titta på ett praktiskt exempel: ett matematiskt bibliotek för att arbeta med flyttal. Inbyggd kod i C++ utför beräkningar mer effektivt än Kotlin, tack vare direkt åtkomst till NEON ARM-instruktioner och frånvaro av array-gränskontroller vid körning. Detta exempel visar det typiska mönstret för NDK-användning — att flytta tunga beräkningar till det inbyggda lagret.
#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);
// Beräknar medelvärde och standardavvikelse
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);
// Normalisering: (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;
}
För felsökning av inbyggd kod, använd makrot __android_log_print från biblioteket android/log.h. Meddelanden visas i Logcat bredvid Java/Kotlin-loggar. Loggningsnivån (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) hjälper till att filtrera meddelanden.
#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++) {
// Tung bearbetning
LOGD("Item %d processed", i);
}
LOGD("Processing complete");
}
Vanliga frågor
Nej. För de flesta appar räcker SDK i Kotlin. NDK behövs för högpresterande uppgifter: realtidsljud/videobearbetning, 3D-grafik, kryptografi eller återanvändning av befintliga C/C++-projekt.
NDK använder Clang från LLVM toolchain. Från och med NDK r23 har GCC helt tagits bort. Clang korskompilerar kod för alla Android ABI:er: arm64-v8a, armeabi-v7a, x86_64, x86.
ABI (Application Binary Interface) — format på maskinkod som bestämmer kompatibilitet med processorn. NDK bygger .so-bibliotek för varje ABI separat. arm64-v8a — det huvudsakliga ABI:t för moderna Android-enheter.
Ja. Android Studio stöder LLDB — felsökare för inbyggd kod. Man kan placera brytpunkter i C++-filer, visa variabler och anropsstacken. För funktion krävs NDK och LLDB-plugin.
Varje inbyggt bibliotek lägger till 100 kB — flera MB i APK:n. För varje ABI krävs ett separat .so-bibliotek. Android App Bundle levererar till användaren endast lämplig arkitektur, vilket minskar installationsstorleken.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också