NDK (Native Development Kit) — مجموعهای از ابزارها برای نوشتن بخشی از برنامه به زبان C و C++ در اندروید است. برخلاف Android SDK معمولی، NDK کد را به کتابخانههای بومی (.so) کامپایل میکند که مستقیماً روی پردازنده بدون لایه ماشین مجازی کار میکنند. به گفته Google NDK Guides, 2026، NDK برای محاسبات با عملکرد بالا، بازیها، پردازش صدا و استفاده مجدد از پروژههای C/C++ موجود استفاده میشود. JNI (Java Native Interface) کد بومی را با Kotlin و Java مرتبط میکند.
نکات اصلی
NDK (Native Development Kit) — مجموعهای از ابزارها برای کامپایل متقابل کد C و C++ به کتابخانههای اجرایی برای اندروید است. NDK شامل کامپایلر Clang، کتابخانه استاندارد libc++، فایلهای هدر Android API و ابزارهای ساخت است. توسعهدهنده کد بومی را به زبان C یا C++ مینویسد، آن را به فایلهای .so (اشیاء مشترک) کامپایل میکند و از طریق JNI به برنامه متصل میکند.
NDK جایگزین Android SDK نمیشود، بلکه آن را تکمیل میکند. تمام UI، چرخه حیات و سرویسهای سیستمی در Kotlin یا Java باقی میمانند. کد بومی وظایف محدودی را حل میکند: محاسبات ریاضی، رمزنگاری، کدکها، فیزیک در بازیها. Google توصیه میکند فقط زمانی از NDK استفاده کنید که SDK عملکرد یا دسترسی به قابلیتهای سختافزاری مورد نیاز را فراهم نمیکند.
تاریخچه NDK از سال 2009 (NDK r1) آغاز میشود. در این مدت ابزارها از یک مجموعه آزمایشی اسکریپتها به یک سیستم بالغ با پشتیبانی از CMake، دیباگ LLDB و پروفایلینگ تبدیل شدهاند. در سال 2026 نسخه فعلی NDK r27 با Clang 19، پشتیبانی کامل از C++20 و libc++ به عنوان تنها کتابخانه استاندارد است.
NDK به توسعهدهنده دسترسی به قابلیتهای سطح پایین اندروید را از طریق APIهای بومی میدهد. سناریوهای اصلی استفاده شامل: کار با OpenGL ES و Vulkan برای گرافیک سهبعدی، پردازش صدا از طریق 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 | سیستم ساخت کتابخانههای بومی |
| LLDB | دیباگر کد بومی در Android Studio |
| ndk-build | سیستم ساخت قدیمی (جایگزین شده با CMake) |
انتخاب بین NDK و SDK خالص به وظیفه بستگی دارد. Android SDK APIهای آماده Java/Kotlin را برای 90% سناریوها فراهم میکند — کار با شبکه، فایلها، اعلانها، دوربین. NDK زمانی متصل میشود که این APIها عملکرد یا قابلیتهای مورد نیاز را فراهم نمیکنند. به عنوان مثال، پردازش صدا در زمان واقعی از طریق SDK امکانپذیر است، اما با تأخیر 50–200 میلیثانیه، در حالی که کتابخانه بومی از طریق Oboe تأخیر را به 5–15 میلیثانیه کاهش میدهد.
اندازه APK — عامل دیگری است. افزودن NDK اندازه برنامه را افزایش میدهد، زیرا هر معماری ABI به یک کتابخانه .so جداگانه نیاز دارد. با این حال استفاده از Android App Bundle (AAB) مشکل را کاهش میدهد: Google Play فقط کتابخانه مربوط به معماری دستگاه کاربر را تحویل میدهد. یک پروژه بومی معمولی 1–10 مگابایت به اندازه نصب روی دستگاه اضافه میکند.
| معیار | SDK (Kotlin/Java) | NDK (C/C++) |
|---|---|---|
| عملکرد | متوسط (کامپایل JIT/AOT) | بالا (کد ماشین) |
| تأخیر صدا | 50–200 میلیثانیه | 5–15 میلیثانیه از طریق Oboe |
| گرافیک سهبعدی | از طریق Canvas/OpenGL Kotlin API | مستقیماً Vulkan/OpenGL |
| پیچیدگی توسعه | کم | زیاد (مدیریت حافظه، JNI) |
| قابلیت انتقال کد | فقط اندروید | لینوکس، ویندوز، macOS، iOS |
| اندازه APK | حداقل | +1–10 مگابایت به ازای هر کتابخانه |
NDK جدا از Android SDK از طریق SDK Manager نصب میشود. در داخل دایرکتوری NDK، toolchain (کامپایلرها)، کتابخانههای پلتفرمی، فایلهای هدر و ابزارها قرار دارند. Toolchain NDK شامل Clang برای کامپایل متقابل برای همه ABIهای هدف است: arm64-v8a، armeabi-v7a، x86_64 و x86. کامپایلر به طور خودکار معماری مناسب را بر اساس پرچمهای CMake یا ndk-build انتخاب میکند.
APIهای اندروید برای کد بومی توسط فایلهای هدر در دایرکتوری sysroot/usr/include نمایش داده میشوند. در آنجا اعلانهایی برای همه APIهای قابل دسترس در کد بومی وجود دارد: native_activity.h برای چرخه حیات 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/ // فایل toolchain CMake
از طریق NDK گروههای زیر از APIهای بومی قابل دسترسی هستند: Native App Glue (مدیریت چرخه حیات Activity از C)، OpenGL ES 3.2 و Vulkan 1.3 (گرافیک)، Oboe (صدای با تأخیر کم)، Neural Networks API (یادگیری ماشین روی دستگاه). هر API یک فایل هدر و کتابخانه استاتیک/دینامیک در ترکیب NDK دارد.
برای کار با APIهای بومی نیازی به JNI نیست — توابع مستقیماً از کد C/C++ فراخوانی میشوند. با این حال برای تعامل با UI در Kotlin همچنان JNI مورد نیاز است. چنین معماری هیبریدی در موتورهای بازی یافت میشود: گرافیک و فیزیک در C++ (از طریق Vulkan)، منو و UI در Kotlin (از طریق Jetpack Compose).
JNI (Java Native Interface) — مکانیزم استاندارد برای فراخوانی کد بومی از ماشین مجازی 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 هنگام ساخت پروژه اگر externalNativeBuild در build.gradle پیکربندی شده باشد به طور خودکار CMake را فراخوانی میکند. CMake فایلهای make را برای هر ABI هدف تولید میکند و کد بومی را به صورت موازی کامپایل میکند.
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")
# اتصال فایلهای هدر
include_directories(src/main/cpp/include)
# ایجاد کتابخانه بومی
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/math_utils.cpp
src/main/cpp/audio_processor.cpp
)
# اتصال کتابخانههای سیستم اندروید
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 کد بومی را جداگانه برای هر ABI مشخص شده کامپایل میکند. رایجترین ABIها در سال 2026: arm64-v8a (99% دستگاههای مدرن)، armeabi-v7a (دستگاههای قدیمی 32 بیتی)، x86_64 (شبیهساز و Chromebook).
تعیین abiFilters در build.gradle ساخت را فقط به معماریهای مورد نیاز محدود میکند که زمان کامپایل را کاهش میدهد. برای Google Play توصیه میشود تمام ABIهایی که کتابخانه با آنها سازگار است گنجانده شود — این کار عملکرد روی همه دستگاهها را تضمین میکند. Google Play Console امکان پیکربندی تحویل APK مخصوص ABI را از طریق 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 بیتی | شبیهسازهای قدیمی |
بیایید یک مثال عملی را بررسی کنیم: کتابخانه ریاضی برای کار با اعداد ممیز شناور. کد بومی در C++ به دلیل دسترسی مستقیم به دستورالعملهای NEON ARM و عدم بررسی مرزهای آرایه در زمان اجرا، محاسبات را کارآمدتر از Kotlin انجام میدهد. این مثال الگوی معمول استفاده از NDK — انتقال محاسبات سنگین به لایه بومی را نشان میدهد.
#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;
}
برای دیباگ کد بومی از ماکرو __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 لازم است برای وظایف با عملکرد بالا: پردازش صدا/ویدئو در زمان واقعی، گرافیک سهبعدی، رمزنگاری یا استفاده مجدد از پروژههای C/C++ موجود.
NDK از Clang از LLVM toolchain استفاده میکند. از NDK r23 به بعد GCC به طور کامل حذف شده است. Clang کد را برای همه ABIهای اندروید به صورت متقابل کامپایل میکند: arm64-v8a, armeabi-v7a, x86_64, x86.
ABI (Application Binary Interface) — فرمت کد ماشین است که سازگاری با پردازنده را تعیین میکند. NDK کتابخانههای .so را برای هر ABI جداگانه میسازد. arm64-v8a — ABI اصلی برای دستگاههای مدرن اندروید.
بله. Android Studio از LLDB — دیباگر کد بومی پشتیبانی میکند. میتوان در فایلهای C++ نقاط توقف (breakpoint) گذاشت، متغیرها و پشته فراخوانی را مشاهده کرد. برای کار به NDK و پلاگین LLDB نیاز است.
هر کتابخانه بومی 100 کیلوبایت تا چند مگابایت به APK اضافه میکند. برای هر ABI یک کتابخانه .so جداگانه نیاز است. Android App Bundle فقط معماری مناسب را به کاربر تحویل میدهد و اندازه نصب را کاهش میدهد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.