NDK (Native Development Kit), Android için uygulamanın bölümlerini C ve C++ ile yazmaya yarayan bir araç takımıdır. Normal Android SDK'nın aksine, NDK kodu yerel kütüphanelere (.so) derleyerek sanal makine katmanı olmadan doğrudan işlemciyle çalışır. Google NDK Kılavuzları, 2026'ya göre NDK, yüksek performanslı hesaplama, oyunlar, ses işleme ve mevcut C/C++ projelerinin yeniden kullanımı için kullanılır. JNI (Java Yerel Arayüzü) yerel kodu Kotlin ve Java ile birleştirir.
Önemli Noktalar
NDK (Native Development Kit), C ve C++ kodunu Android için yürütülebilir kütüphanelere çapraz derlemek için bir araç setidir. NDK, Clang derleyicisini, libc++ standart kütüphanesini, Android API başlık dosyalarını ve derleme yardımcı programlarını içerir. Geliştirici, C veya C++ ile yerel kod yazar, bunu .so dosyalarına (paylaşılan nesneler) derler ve JNI aracılığıyla uygulamaya bağlar.
NDK, Android SDK'nın yerini almaz, onu tamamlar. Tüm kullanıcı arayüzü, yaşam döngüsü ve sistem hizmetleri Kotlin veya Java'da kalır. Yerel kod belirli görevleri çözer: matematiksel hesaplamalar, kriptografi, codec'ler, oyunlarda fizik. Google, SDK'nın gerekli performansı veya donanım yeteneklerine erişimi sağlamadığı durumlarda NDK kullanılmasını önerir.
NDK'nin tarihi 2009'a (NDK r1) dayanır. Bu süre zarfında araç takımı, deneysel bir betik koleksiyonundan CMake, LLDB hata ayıklama ve profil oluşturma desteğine sahip olgun bir sisteme dönüştü. 2026 itibarıyla güncel sürüm, Clang 19, tam C++20 desteği ve tek standart kütüphane olarak libc++ ile NDK r27'dir.
NDK, geliştiriciye yerel API'ler aracılığıyla Android'in düşük seviyeli yeteneklerine erişim sağlar. Ana kullanım durumları şunları içerir: 3D grafikler için OpenGL ES ve Vulkan ile çalışma, Oboe ile ses işleme, BoringSSL ile kriptografik işlemler ve ARM için NEON optimizasyonları. Tüm bu API'ler C/C++'tan kullanılabilir ve derleme için NDK gerektirir.
Ayrıca NDK, mevcut C/C++ kütüphanelerinin Kotlin'de yeniden yazılmadan yeniden kullanılmasına olanak tanır. Bu, özellikle C++'da uzun geçmişi olan projeler için önemlidir — oyun motorları (Unity, Unreal Engine), bilgisayarlı görü kütüphaneleri (OpenCV) veya kriptografik paketler (OpenSSL). Bu gibi durumlarda NDK, yıllarca sürecek geliştirmeyi önler.
| Bileşen | Amaç |
|---|---|
| Clang | C++20 desteğiyle C/C++ derleyicisi |
| libc++ | Standart C++ kütüphanesi (NDK r27'de tek) |
| CMake | Yerel kütüphaneler için derleme sistemi |
| LLDB | Android Studio'da yerel kod hata ayıklayıcısı |
| ndk-build | Eski derleme sistemi (CMake ile değiştirildi) |
NDK ve saf SDK arasındaki seçim göreve bağlıdır. Android SDK, senaryoların %90'ı için hazır Java/Kotlin API'leri sağlar — ağ, dosyalar, bildirimler, kamera. NDK, bu API'ler gerekli performansı veya işlevselliği sağlamadığında kullanılır. Örneğin, SDK aracılığıyla gerçek zamanlı ses işleme mümkündür ancak 50–200 ms gecikmeyle, Oboe aracılığıyla yerel bir kütüphane gecikmeyi 5–15 ms'ye düşürür.
APK boyutu başka bir faktördür. NDK eklemek, her ABI mimarisi ayrı bir .so kütüphanesi gerektirdiğinden uygulama boyutunu artırır. Ancak, Android App Bundle (AAB) kullanımı sorunu hafifletir: Google Play, kullanıcıya yalnızca kendi mimarisi için kütüphaneyi iletir. Tipik bir yerel proje, cihaz başına kurulum boyutuna 1–10 MB ekler.
| Kriter | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| Performans | Orta (JIT/AOT derleme) | Yüksek (makine kodu) |
| Ses gecikmesi | 50–200 ms | Oboe ile 5–15 ms |
| 3D grafikler | Canvas/OpenGL Kotlin API ile | Vulkan/OpenGL doğrudan |
| Geliştirme karmaşıklığı | Düşük | Yüksek (bellek yönetimi, JNI) |
| Kod taşınabilirliği | Sadece Android | Linux, Windows, macOS, iOS |
| APK boyutu | Minimum | +1–10 MB/kütüphane |
NDK, SDK Manager aracılığıyla Android SDK'dan ayrı olarak kurulur. NDK dizini içinde araç zinciri (derleyiciler), platform kütüphaneleri, başlık dosyaları ve yardımcı programlar bulunur. NDK Araç Zinciri, tüm hedef ABI'ler (arm64-v8a, armeabi-v7a, x86_64 ve x86) için çapraz derleme yapan Clang'ı içerir. Derleyici, CMake veya ndk-build bayraklarına göre gerekli mimariyi otomatik olarak seçer.
Yerel kod için Android API'leri, sysroot/usr/include dizinindeki başlık dosyaları tarafından sağlanır. Burada yerel kodda bulunan tüm API'lerin bildirimleri bulunur: Activity yaşam döngüsü için native_activity.h, giriş olayları için input.h, sensörler için sensor.h. Bu başlıkları dahil etmek, JNI katmanı olmadan donanım yeteneklerine erişim sağlar.
ndk/
toolchains/
llvm/prebuilt/windows-x86_64/
bin/ // Clang, ld, llvm-profdata
sysroot/ // Android API başlık dosyaları
platforms/
android-26/ // API 26 için libc, libm, libdl
android-34/
sources/
cxx-stl/ // libc++ başlıkları
build/
cmake/ // CMake araç zinciri dosyası
NDK aracılığıyla aşağıdaki yerel API grupları kullanılabilir: Native App Glue (C'den Activity yaşam döngüsü yönetimi), OpenGL ES 3.2 ve Vulkan 1.3 (grafikler), Oboe (düşük gecikmeli ses), Neural Networks API (cihaz üzerinde makine öğrenimi). Her API'nin NDK'nin parçası olarak bir başlık dosyası ve statik/dinamik kütüphanesi vardır.
Yerel API'lerle çalışmak JNI gerektirmez — işlevler doğrudan C/C++ kodundan çağrılır. Ancak, Kotlin kullanıcı arayüzü ile etkileşim hâlâ JNI gerektirir. Bu hibrit mimari, oyun motorlarında yaygındır: C++ ile grafik ve fizik (Vulkan aracılığıyla), Kotlin ile menüler ve kullanıcı arayüzü (Jetpack Compose aracılığıyla).
JNI (Java Yerel Arayüzü), Java/Kotlin sanal makinesinden yerel kodu çağırmak için standart bir mekanizmadır. Geliştirici, Kotlin'de external anahtar sözcüğüyle bir dış işlev bildirir ve System.loadLibrary aracılığıyla .so kütüphanesini yükler. C++ tarafında, işlev, paketi ve sınıf adını kodlayan JNI adlandırma kuralı kullanılarak bildirilir.
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
}
// Kodda kullanım
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, eski ndk-build'in yerini alan NDK için birincil derleme sistemidir. CMakeLists.txt dosyası kaynak dosyaları, kütüphaneleri ve derleme bayraklarını tanımlar. Android Studio, build.gradle'da externalNativeBuild yapılandırılmışsa, projeyi derlerken otomatik olarak CMake'i çağırır. CMake, her hedef ABI için makefile'lar oluşturur ve yerel kodu paralel olarak derler.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# Başlık dosyalarını dahil et
include_directories(src/main/cpp/include)
# Yerel kütüphane oluştur
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# Android sistem kütüphanelerini bağla
target_link_libraries(
native-lib
android
log
OpenSLES
# libc++ otomatik olarak bağlanır
)
# Optimizasyon bayrakları
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)
android {
defaultConfig {
ndk {
// Derleme için hedef ABI'ler
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 (Uygulama İkili Arayüzü), cihazın işlemcisiyle uyumluluğu belirleyen makine kodu formatıdır. Her ARM veya x86 mimarisinin kendi ABI'si vardır. NDK, yerel kodu belirtilen her ABI için ayrı ayrı derler. 2026 itibarıyla en yaygın ABI'ler: arm64-v8a (modern cihazların %99'u), armeabi-v7a (eski 32-bit cihazlar), x86_64 (emülatör ve Chromebook).
build.gradle'da abiFilters belirtmek, derlemeyi yalnızca gerekli mimarilerle sınırlayarak derleme süresini kısaltır. Google Play için kütüphanenin desteklediği tüm ABI'lerin dahil edilmesi önerilir — bu, tüm cihazlarda çalışmasını garanti eder. Google Play Console, App Bundle aracılığıyla ABI'ye özel APK dağıtımını yapılandırmaya olanak tanır.
#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 | Mimari | Bit | Cihazlar |
|---|---|---|---|
| arm64-v8a | ARMv8-A | 64-bit | Neredeyse tüm modern telefonlar |
| armeabi-v7a | ARMv7-A | 32-bit | Eski cihazlar (2020 öncesi) |
| x86_64 | x86-64 | 64-bit | Emülatör, Chromebook |
| x86 | x86 IA-32 | 32-bit | Eski emülatörler |
Pratik bir örnek ele alalım: kayan noktalı sayılarla çalışmak için bir matematik kütüphanesi. C++'taki yerel kod, ARM NEON talimatlarına doğrudan erişim ve çalışma zamanında dizi sınır kontrollerinin olmaması sayesinde Kotlin'den daha verimli hesaplama yapar. Bu örnek, NDK'nin tipik bir kullanım modelini gösterir — ağır hesaplamaları yerel katmana taşıma.
#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);
// Ortalama ve standart sapmayı hesapla
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);
// Normalleştirme: (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;
}
Yerel kodda hata ayıklamak için android/log.h kütüphanesindeki __android_log_print makrosunu kullanın. Mesajlar, Java/Kotlin günlüklerinin yanında Logcat'te görünür. Günlük düzeyi (ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR) mesajları filtrelemeye yardımcı olur.
#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++) {
// Ağır işleme
LOGD("Item %d processed", i);
}
LOGD("Processing complete");
}
Sıkça Sorulan Sorular
Hayır. Çoğu uygulama için Kotlin SDK yeterlidir. NDK gereklidir yüksek performanslı görevler için: gerçek zamanlı ses/video işleme, 3D grafikler, kriptografi veya mevcut C/C++ projelerinin yeniden kullanımı.
NDK, LLVM araç zincirinden Clang kullanır. NDK r23'ten itibaren GCC tamamen kaldırılmıştır. Clang, tüm Android ABI'leri (arm64-v8a, armeabi-v7a, x86_64, x86) için çapraz derleme yapar.
ABI (Uygulama İkili Arayüzü), işlemciyle uyumluluğu belirleyen makine kodu formatıdır. NDK, her ABI için ayrı ayrı .so kütüphaneleri oluşturur. arm64-v8a modern Android cihazlar için birincil ABI'dir.
Evet. Android Studio, LLDB'yi (bir yerel kod hata ayıklayıcısı) destekler. C++ dosyalarında kesme noktaları belirleyebilir, değişkenleri ve çağrı yığınını görebilirsiniz. NDK ve LLDB eklentisi gereklidir.
Her yerel kütüphane APK'ye 100 KB ile birkaç MB arasında ekler. Her ABI ayrı bir .so kütüphanesi gerektirir. Android App Bundle, kullanıcıya yalnızca uygun mimariyi ileterek kurulum boyutunu azaltır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun