NDK (Native Development Kit) — алат за писање дела апликације у C и C++ под Android-ом. За разлику од обичног Android SDK, NDK компајлира код у native библиотеке (.so) које раде директно са процесором без слоја виртуелне машине. Према Google NDK Guides, 2026, NDK се користи за високоперформансна израчунавања, игре, обраду звука и поновну употребу постојећих C/C++ пројеката. JNI (Java Native Interface) повезује native код са Kotlin и Java.
Главно
NDK (Native Development Kit) — скуп алата за унакрсно компајлирање C и C++ кода у извршне библиотеке за Android. NDK укључује компајлер Clang, стандардну библиотеку libc++, заглавне датотеке Android API и алате за изградњу. Програмер пише native код у C или C++, компајлира га у .so датотеке (shared objects) и повезује са апликацијом кроз JNI.
NDK не замењује Android SDK, већ га допуњава. Цео UI, lifecycle и системски сервиси остају у Kotlin или Java. Native код решава уске задатке: математичка израчунавања, криптографију, кодека, физику у играма. Google препоручује коришћење NDK само када SDK не обезбеђује потребне перформансе или приступ хардверским могућностима.
Историја NDK почиње 2009. године (NDK r1). За то време алати су прешли пут од експерименталног скупа скрипти до зрелог система са подршком за CMake, LLDB отклањање грешака и профилисање. Од 2026. године актуелна верзија је NDK r27 са Clang 19, пуном подршком за C++20 и libc++ као једином стандардном библиотеком.
NDK програмеру даје приступ нискоризичним могућностима Android-а кроз native API. Главни сценарији употребе укључују: рад са OpenGL ES и Vulkan за 3D графику, обраду звука кроз Oboe, криптографске операције кроз BoringSSL и NEON оптимизације за ARM. Сви ови API-ји су доступни из C/C++ и захтевају NDK за компајлирање.
Поред тога, NDK омогућава поновну употребу постојећих C/C++ библиотека без преписивања у Kotlin. Ово је посебно важно за пројекте са дугогодишњом историјом на C++ — погоне игара (Unity, Unreal Engine), библиотеке компјутерског вида (OpenCV) или криптографске пакете (OpenSSL). У таквим случајевима NDK штеди године развоја.
| Компонента | Намена |
|---|---|
| Clang | Компајлер C/C++ са подршком за C++20 |
| libc++ | Стандардна библиотека C++ (једина у NDK r27) |
| CMake | Систем изградње native библиотека |
| LLDB | Дебагер native кода у Android Studio |
| ndk-build | Застарели систем изградње (замењен CMake-ом) |
Избор између NDK и чистог SDK зависи од задатка. Android SDK пружа готове Java/Kotlin API-је за 90% сценарија — рад са мрежом, датотекама, обавештењима, камером. NDK се повезује када ови API-ји не обезбеђују потребне перформансе или функционалност. На пример, обрада звука у реалном времену кроз SDK је могућа, али са кашњењем од 50–200 ms, док native библиотека кроз Oboe смањује кашњење на 5–15 ms.
Величина APK — још један фактор. Додавање NDK повећава величину апликације, јер свака ABI архитектура захтева засебну .so библиотеку. Међутим, употреба Android App Bundle (AAB) ублажава проблем: Google Play испоручује кориснику само библиотеку за његову архитектуру. Типичан native пројекат додаје 1–10 MB величини инсталације на уређају.
| Критеријум | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Перформансе | Средње (JIT/AOT компајлирање) | Високе (машински код) |
| Кашњење звука | 50–200 ms | 5–15 ms кроз Oboe |
| 3D графика | Кроз Canvas/OpenGL Kotlin API | Vulkan/OpenGL директно |
| Сложеност развоја | Ниска | Висока (управљање меморијом, JNI) |
| Преносивост кода | Само Android | Linux, Windows, macOS, iOS |
| Величина APK | Минимална | +1–10 MB по библиотеци |
NDK се инсталира одвојено од Android SDK кроз SDK Manager. Унутар NDK директоријума налазе се toolchain (компајлери), платформске библиотеке, заглавне датотеке и алати. NDK Toolchain укључује Clang за унакрсно компајлирање за све циљне ABI-је: arm64-v8a, armeabi-v7a, x86_64 и x86. Компајлер аутоматски бира потребну архитектуру на основу CMake или ndk-build флагова.
Android API за native код представљени су заглавним датотекама у директоријуму sysroot/usr/include. Тамо се налазе декларације за све API-је доступне у native коду: native_activity.h за lifecycle Activity, input.h за догађаје уноса, sensor.h за сензоре. Повезивање ових заглавља даје приступ хардверским могућностима без JNI слоја.
ndk/
toolchains/
llvm/prebuilt/windows-x86_64/
bin/ // Clang, ld, llvm-profdata
sysroot/ // Заглавне датотеке Android API
platforms/
android-26/ // libc, libm, libdl за API 26
android-34/
sources/
cxx-stl/ // libc++ заглавља
build/
cmake/ // CMake toolchain датотека
Кроз NDK доступне су следеће групе native API-ја: Native App Glue (управљање lifecycle Activity из C), OpenGL ES 3.2 и Vulkan 1.3 (графика), Oboe (звук са ниским кашњењем), Neural Networks API (машинско учење на уређају). Сваки API има заглавну датотеку и статичку/динамичку библиотеку у саставу NDK.
За рад са native API-јима није потребан JNI — функције се позивају директно из C/C++ кода. Међутим, за интеракцију са UI-јем у Kotlin и даље је потребан JNI. Таква хибридна архитектура среће се у погонима игара: графика и физика у C++ (кроз Vulkan), мени и UI у Kotlin (кроз Jetpack Compose).
JNI (Java Native Interface) — стандардни механизам позивања native кода из виртуелне машине Java/Kotlin. Програмер декларише у Kotlin спољну функцију са кључном речи external и повезује .so библиотеку кроз System.loadLibrary. На страни C++, функција се декларише коришћењем конвенције именовања JNI која кодира пакет и име класе.
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
}
// Употреба у коду
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 — основни систем изградње за NDK, који је заменио застарели ndk-build. Датотека CMakeLists.txt описује изворне датотеке, библиотеке и флагове компајлирања. Android Studio аутоматски позива CMake при изградњи пројекта ако је подешен externalNativeBuild у build.gradle. CMake генерише make датотеке за сваки циљни ABI и компајлира native код паралелно.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# Повезивање заглавних датотека
include_directories(src/main/cpp/include)
# Креирање native библиотеке
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# Повезивање системских библиотека Android-а
target_link_libraries(
native-lib
android
log
OpenSLES
# libc++ се повезује аутоматски
)
# Флагови оптимизације
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)
android {
defaultConfig {
ndk {
// Циљни ABI-ји за изградњу
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) — формат машинског кода који одређује компатибилност са процесором уређаја. Свака ARM или x86 архитектура има свој ABI. NDK компајлира native код засебно за сваки наведени ABI. Најраспрострањенији ABI-ји у 2026: arm64-v8a (99% модерних уређаја), armeabi-v7a (стари 32-битни уређаји), x86_64 (емулатор и Chromebook).
Навођење abiFilters у build.gradle ограничава изградњу само на потребне архитектуре, што скраћује време компајлирања. За Google Play препоручује се укључивање свих ABI-ја са којима је библиотека компатибилна — то гарантује рад на свим уређајима. Google Play Console омогућава подешавање испоруке ABI-специфичних APK-ова кроз 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 | Архитектура | Битност | Уређаји |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-битни | Скоро сви модерни телефони |
| armeabi-v7a | ARMv7-A | 32-битни | Стари уређаји (до 2020) |
| x86_64 | x86-64 | 64-битни | Емулатор, Chromebook |
| x86 | x86 IA-32 | 32-битни | Застарели емулатори |
Размотримо практичан пример: математичка библиотека за рад са бројевима са покретним зарезом. Native код у C++ обавља израчунавања ефикасније од Kotlin-а захваљујући директном приступу NEON инструкцијама ARM и одсуству провера граница низова у runtime. Овај пример демонстрира типичан образац употребе NDK — изношење тешких израчунавања у native слој.
#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);
// Израчунавамо средњу вредност и стандардну девијацију
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);
// Нормализација: (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;
}
За отклањање грешака у native коду користите макро __android_log_print из библиотеке android/log.h. Поруке се појављују у Logcat-у поред Java/Kotlin логова. Ниво логирања (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) помаже у филтрирању порука.
#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++) {
// Тешка обрада
LOGD("Item %d processed", i);
}
LOGD("Processing complete");
}
Често постављана питања
Не. За већину апликација довољан је SDK у Kotlin. NDK је потребан за високоперформансне задатке: обрада звука/видеа у реалном времену, 3D графика, криптографија или поновна употреба постојећих C/C++ пројеката.
NDK користи Clang из LLVM toolchain-а. Од NDK r23 GCC је потпуно уклоњен. Clang унакрсно компајлира код за све Android ABI: arm64-v8a, armeabi-v7a, x86_64, x86.
ABI (Application Binary Interface) — формат машинског кода који одређује компатибилност са процесором. NDK гради .so библиотеке за сваки ABI посебно. arm64-v8a — главни ABI за модерне Android уређаје.
Да. Android Studio подржава LLDB — дебагер native кода. Могу се постављати breakpoint-ови у C++ датотекама, прегледати променљиве и стек позива. За рад су потребни NDK и LLDB прикључак.
Свака native библиотека додаје 100 KB — неколико MB у APK. За сваки ABI потребна је засебна .so библиотека. Android App Bundle испоручује кориснику само одговарајућу архитектуру, смањујући величину инсталације.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође