NDK (Native Development Kit) — este un set de instrumente pentru scrierea unei părți a aplicației în C și C++ pentru Android. Spre deosebire de Android SDK obișnuit, NDK compilează codul în biblioteci native (.so) care rulează direct pe procesor fără un strat de mașină virtuală. Potrivit Google NDK Guides, 2026, NDK este utilizat pentru calcule de înaltă performanță, jocuri, procesare audio și reutilizarea proiectelor C/C++ existente. JNI (Java Native Interface) leagă codul nativ cu Kotlin și Java.
Principalele
NDK (Native Development Kit) — este un set de instrumente pentru cross-compilarea codului C și C++ în biblioteci executabile pentru Android. NDK include compilatorul Clang, biblioteca standard libc++, fișierele header ale Android API și utilitare de build. Dezvoltatorul scrie cod nativ în C sau C++, îl compilează în fișiere .so (shared objects) și îl conectează la aplicație prin JNI.
NDK nu înlocuiește Android SDK, ci îl completează. Întregul UI, lifecycle și serviciile sistem rămân în Kotlin sau Java. Codul nativ rezolvă sarcini restrânse: calcule matematice, criptografie, codecuri, fizică în jocuri. Google recomandă utilizarea NDK doar atunci când SDK nu asigură performanța necesară sau accesul la capacitățile hardware.
Istoria NDK începe în 2009 (NDK r1). În acest timp, instrumentele au parcurs drumul de la un set experimental de scripturi la un sistem matur cu suport CMake, depanare LLDB și profilare. În 2026, versiunea actuală este NDK r27 cu Clang 19, suport complet pentru C++20 și libc++ ca unică bibliotecă standard.
NDK oferă dezvoltatorului acces la capabilități de nivel scăzut ale Android prin API-uri native. Principalele scenarii de utilizare includ: lucrul cu OpenGL ES și Vulkan pentru grafică 3D, procesarea audio prin Oboe, operațiuni criptografice prin BoringSSL și optimizări NEON pentru ARM. Toate aceste API-uri sunt accesibile din C/C++ și necesită NDK pentru compilare.
În plus, NDK permite reutilizarea bibliotecilor C/C++ existente fără rescrierea în Kotlin. Acest lucru este deosebit de relevant pentru proiecte cu o istorie îndelungată în C++ — motoare de jocuri (Unity, Unreal Engine), biblioteci de viziune computerizată (OpenCV) sau pachete criptografice (OpenSSL). În astfel de cazuri, NDK economisește ani de dezvoltare.
| Componentă | Destinație |
|---|---|
| Clang | Compilator C/C++ cu suport C++20 |
| libc++ | Bibliotecă standard C++ (unică în NDK r27) |
| CMake | Sistem de build pentru biblioteci native |
| LLDB | Depanator de cod nativ în Android Studio |
| ndk-build | Sistem de build învechit (înlocuit cu CMake) |
Alegerea între NDK și SDK pur depinde de sarcină. Android SDK oferă API-uri Java/Kotlin gata făcute pentru 90% din scenarii — lucrul cu rețeaua, fișiere, notificări, cameră. NDK este conectat când aceste API-uri nu asigură performanța sau funcționalitatea necesară. De exemplu, procesarea audio în timp real prin SDK este posibilă, dar cu întârzieri de 50–200 ms, în timp ce o bibliotecă nativă prin Oboe reduce întârzierea la 5–15 ms.
Dimensiunea APK — un alt factor. Adăugarea NDK mărește dimensiunea aplicației, deoarece fiecare arhitectură ABI necesită o bibliotecă .so separată. Cu toate acestea, utilizarea Android App Bundle (AAB) atenuează problema: Google Play livrează utilizatorului doar biblioteca pentru arhitectura sa. Un proiect nativ tipic adaugă 1–10 MB la dimensiunea instalării pe dispozitiv.
| Criteriu | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Performanță | Medie (compilare JIT/AOT) | Ridicată (cod mașină) |
| Întârziere audio | 50–200 ms | 5–15 ms prin Oboe |
| Grafică 3D | Prin Canvas/OpenGL Kotlin API | Vulkan/OpenGL direct |
| Complexitate dezvoltare | Scăzută | Ridicată (gestionare memorie, JNI) |
| Portabilitate cod | Doar Android | Linux, Windows, macOS, iOS |
| Dimensiune APK | Minimă | +1–10 MB per bibliotecă |
NDK se instalează separat de Android SDK prin SDK Manager. În interiorul directorului NDK se află toolchain (compilatoare), biblioteci de platformă, fișiere header și utilitare. Toolchain NDK include Clang pentru cross-compilare pentru toate ABI-urile țintă: arm64-v8a, armeabi-v7a, x86_64 și x86. Compilatorul selectează automat arhitectura necesară pe baza flag-urilor CMake sau ndk-build.
API-urile Android pentru cod nativ sunt reprezentate de fișiere header în directorul sysroot/usr/include. Acolo se găsesc declarațiile pentru toate API-urile disponibile în codul nativ: native_activity.h pentru lifecycle Activity, input.h pentru evenimente de intrare, sensor.h pentru senzori. Conectarea acestor header-e oferă acces la capacitățile hardware fără stratul JNI.
ndk/
toolchains/
llvm/prebuilt/windows-x86_64/
bin/ // Clang, ld, llvm-profdata
sysroot/ // Fișiere header Android API
platforms/
android-26/ // libc, libm, libdl pentru API 26
android-34/
sources/
cxx-stl/ // Header-e libc++
build/
cmake/ // Fișier toolchain CMake
Prin NDK sunt disponibile următoarele grupuri de API-uri native: Native App Glue (gestionarea lifecycle Activity din C), OpenGL ES 3.2 și Vulkan 1.3 (grafică), Oboe (audio cu latență scăzută), Neural Networks API (învățare automată pe dispozitiv). Fiecare API are un fișier header și o bibliotecă statică/dinamică în componența NDK.
Pentru lucrul cu API-urile native nu este necesar JNI — funcțiile sunt apelate direct din codul C/C++. Cu toate acestea, pentru interacțiunea cu UI-ul în Kotlin este totuși necesar JNI. Această arhitectură hibridă se întâlnește în motoarele de jocuri: grafica și fizica în C++ (prin Vulkan), meniul și UI-ul în Kotlin (prin Jetpack Compose).
JNI (Java Native Interface) — mecanismul standard de apelare a codului nativ din mașina virtuală Java/Kotlin. Dezvoltatorul declară în Kotlin o funcție externă cu cuvântul cheie external și conectează biblioteca .so prin System.loadLibrary. În partea C++, funcția este declarată folosind convenția de denumire JNI care codifică pachetul și numele clasei.
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
}
// Utilizare în cod
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 — sistemul principal de build pentru NDK, care a înlocuit ndk-build învechit. Fișierul CMakeLists.txt descrie fișierele sursă, bibliotecile și flag-urile de compilare. Android Studio apelează automat CMake la build-ul proiectului dacă este configurat externalNativeBuild în build.gradle. CMake generează fișiere make pentru fiecare ABI țintă și compilează codul nativ în paralel.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# Conectarea fișierelor header
include_directories(src/main/cpp/include)
# Crearea bibliotecii native
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# Conectarea bibliotecilor de sistem Android
target_link_libraries(
native-lib
android
log
OpenSLES
# libc++ se conectează automat
)
# Flag-uri de optimizare
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)
android {
defaultConfig {
ndk {
// ABI-uri țintă pentru 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) — este formatul codului mașină care determină compatibilitatea cu procesorul dispozitivului. Fiecare arhitectură ARM sau x86 are propriul ABI. NDK compilează codul nativ separat pentru fiecare ABI specificat. Cele mai răspândite ABI-uri în 2026: arm64-v8a (99% din dispozitivele moderne), armeabi-v7a (dispozitive vechi pe 32 de biți), x86_64 (emulator și Chromebook).
Specificarea abiFilters în build.gradle limitează build-ul doar la arhitecturile necesare, reducând timpul de compilare. Pentru Google Play se recomandă includerea tuturor ABI-urilor cu care biblioteca este compatibilă — aceasta garantează funcționarea pe toate dispozitivele. Google Play Console permite configurarea livrării APK-urilor specifice ABI prin 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 | Arhitectură | Bit | Dispozitive |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-bit | Aproape toate telefoanele moderne |
| armeabi-v7a | ARMv7-A | 32-bit | Dispozitive vechi (până în 2020) |
| x86_64 | x86-64 | 64-bit | Emulator, Chromebook |
| x86 | x86 IA-32 | 32-bit | Emulatoare învechite |
Să examinăm un exemplu practic: o bibliotecă matematică pentru lucrul cu numere în virgulă mobilă. Codul nativ în C++ efectuează calcule mai eficient decât Kotlin, datorită accesului direct la instrucțiunile NEON ARM și absenței verificării limitelor array-urilor în runtime. Acest exemplu demonstrează modelul tipic de utilizare NDK — mutarea calculelor grele în stratul nativ.
#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);
// Calculăm media și deviația standard
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);
// Normalizare: (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;
}
Pentru depanarea codului nativ utilizați macro-ul __android_log_print din biblioteca android/log.h. Mesajele apar în Logcat alături de logurile Java/Kotlin. Nivelul de logare (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) ajută la filtrarea mesajelor.
#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++) {
// Procesare grea
LOGD("Item %d processed", i);
}
LOGD("Processing complete");
}
Întrebări frecvente
Nu. Pentru majoritatea aplicațiilor este suficient SDK în Kotlin. NDK este necesar pentru sarcini de înaltă performanță: procesare audio/video în timp real, grafică 3D, criptografie sau reutilizarea proiectelor C/C++ existente.
NDK utilizează Clang din LLVM toolchain. Începând cu NDK r23, GCC a fost complet eliminat. Clang cross-compilează codul pentru toate ABI-urile Android: arm64-v8a, armeabi-v7a, x86_64, x86.
ABI (Application Binary Interface) — formatul codului mașină care determină compatibilitatea cu procesorul. NDK construiește biblioteci .so pentru fiecare ABI separat. arm64-v8a — ABI principal pentru dispozitivele Android moderne.
Da. Android Studio suportă LLDB — depanatorul de cod nativ. Se pot pune breakpoint-uri în fișierele C++, vizualiza variabile și stiva de apeluri. Pentru funcționare sunt necesare NDK și plugin-ul LLDB.
Fiecare bibliotecă nativă adaugă 100 KB — câțiva MB în APK. Pentru fiecare ABI este necesară o bibliotecă .so separată. Android App Bundle livrează utilizatorului doar arhitectura potrivită, reducând dimensiunea instalării.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și