NDK اندروید: چیست، Native Development Kit و JNI برای C++

نویسنده: IT Sectr منتشر شده: 2026-02-09 زمان مطالعه: 10 دقیقه

NDK (Native Development Kit) — مجموعه‌ای از ابزارها برای نوشتن بخشی از برنامه به زبان C و C++ در اندروید است. برخلاف Android SDK معمولی، NDK کد را به کتابخانه‌های بومی (.so) کامپایل می‌کند که مستقیماً روی پردازنده بدون لایه ماشین مجازی کار می‌کنند. به گفته Google NDK Guides, 2026، NDK برای محاسبات با عملکرد بالا، بازی‌ها، پردازش صدا و استفاده مجدد از پروژه‌های C/C++ موجود استفاده می‌شود. JNI (Java Native Interface) کد بومی را با Kotlin و Java مرتبط می‌کند.

نکات اصلی

  • NDK — مجموعه ابزارهایی برای کامپایل کد C/C++ به کتابخانه‌های بومی در اندروید.
  • JNI — رابط تعامل بین ماشین مجازی Java/Kotlin و کد بومی.
  • CMake — سیستم ساخت اصلی برای پروژه‌های NDK که از طریق CMakeLists.txt پیکربندی می‌شود.
  • ABI — معماری هدف پردازنده (arm64-v8a, armeabi-v7a, x86_64) که کتابخانه برای آن ساخته می‌شود.
  • NDK برای اکثر برنامه‌های اندروید لازم نیست و فقط در کارهایی با نیازهای عملکرد بالا استفاده می‌شود.

NDK چیست

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

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: چه زمانی کد بومی نیاز است

انتخاب بین 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 و NDK بر اساس معیارها

معیار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: ابزارها و کتابخانه‌ها

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

text
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

APIهای بومی اندروید

از طریق 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: چگونه Kotlin C++ را فراخوانی می‌کند

JNI (Java Native Interface) — مکانیزم استاندارد برای فراخوانی کد بومی از ماشین مجازی Java/Kotlin است. توسعه‌دهنده در Kotlin یک تابع خارجی با کلمه کلیدی external اعلام می‌کند و کتابخانه .so را از طریق System.loadLibrary متصل می‌کند. در سمت C++ تابع با استفاده از قرارداد نام‌گذاری JNI که بسته و نام کلاس را رمزگذاری می‌کند اعلام می‌شود.

اعلان تابع بومی در Kotlin

kotlin
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++"

پیاده‌سازی تابع JNI در C++

cpp
#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;
}

پیکربندی CMakeLists.txt برای NDK

CMake — سیستم ساخت اصلی برای NDK است که جایگزین ndk-build قدیمی شده است. فایل CMakeLists.txt فایل‌های منبع، کتابخانه‌ها و پرچم‌های کامپایل را توصیف می‌کند. Android Studio هنگام ساخت پروژه اگر externalNativeBuild در build.gradle پیکربندی شده باشد به طور خودکار CMake را فراخوانی می‌کند. CMake فایل‌های make را برای هر ABI هدف تولید می‌کند و کد بومی را به صورت موازی کامپایل می‌کند.

مثال CMakeLists.txt برای کتابخانه بومی

cmake
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)

پیکربندی build.gradle برای NDK

groovy
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 و ساخت چندپلتفرمی

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 فراهم می‌کند.

تعیین ABI دستگاه در کد بومی

cpp
#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-v8aARMv8-A64 بیتیتقریباً همه تلفن‌های مدرن
armeabi-v7aARMv7-A32 بیتیدستگاه‌های قدیمی (تا 2020)
x86_64x86-6464 بیتیشبیه‌ساز، Chromebook
x86x86 IA-3232 بیتیشبیه‌سازهای قدیمی

نمونه‌های کد بومی در C++

بیایید یک مثال عملی را بررسی کنیم: کتابخانه ریاضی برای کار با اعداد ممیز شناور. کد بومی در C++ به دلیل دسترسی مستقیم به دستورالعمل‌های NEON ARM و عدم بررسی مرزهای آرایه در زمان اجرا، محاسبات را کارآمدتر از Kotlin انجام می‌دهد. این مثال الگوی معمول استفاده از NDK — انتقال محاسبات سنگین به لایه بومی را نشان می‌دهد.

عملیات ریاضی در کد بومی

cpp
#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) به فیلتر کردن پیام‌ها کمک می‌کند.

cpp
#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");
}

سوالات متداول

آیا استفاده از NDK برای توسعه اندروید اجباری است؟

خیر. برای اکثر برنامه‌ها SDK در Kotlin کافی است. NDK لازم است برای وظایف با عملکرد بالا: پردازش صدا/ویدئو در زمان واقعی، گرافیک سه‌بعدی، رمزنگاری یا استفاده مجدد از پروژه‌های C/C++ موجود.

NDK از چه کامپایلری استفاده می‌کند؟

NDK از Clang از LLVM toolchain استفاده می‌کند. از NDK r23 به بعد GCC به طور کامل حذف شده است. Clang کد را برای همه ABIهای اندروید به صورت متقابل کامپایل می‌کند: arm64-v8a, armeabi-v7a, x86_64, x86.

ABI در زمینه NDK چیست؟

ABI (Application Binary Interface) — فرمت کد ماشین است که سازگاری با پردازنده را تعیین می‌کند. NDK کتابخانه‌های .so را برای هر ABI جداگانه می‌سازد. arm64-v8a — ABI اصلی برای دستگاه‌های مدرن اندروید.

آیا می‌توان کد C++ را از طریق NDK دیباگ کرد؟

بله. Android Studio از LLDB — دیباگر کد بومی پشتیبانی می‌کند. می‌توان در فایل‌های C++ نقاط توقف (breakpoint) گذاشت، متغیرها و پشته فراخوانی را مشاهده کرد. برای کار به NDK و پلاگین LLDB نیاز است.

NDK چگونه بر اندازه APK تأثیر می‌گذارد؟

هر کتابخانه بومی 100 کیلوبایت تا چند مگابایت به APK اضافه می‌کند. برای هر ABI یک کتابخانه .so جداگانه نیاز است. Android App Bundle فقط معماری مناسب را به کاربر تحویل می‌دهد و اندازه نصب را کاهش می‌دهد.

خلاصه

  • NDK — مجموعه ابزارهایی برای کامپایل متقابل کد C/C++ به کتابخانه‌های بومی اندروید از طریق کامپایلر Clang.
  • JNI — رابطی که Kotlin/Java را با کد بومی از طریق کلمه کلیدی external و قرارداد نام‌گذاری توابع متصل می‌کند.
  • CMake — سیستم ساخت اصلی NDK که از طریق فایل CMakeLists.txt و externalNativeBuild در Gradle پیکربندی می‌شود.
  • ABI معماری پردازنده را تعیین می‌کند — arm64-v8a، armeabi-v7a، x86_64. هر ABI نیاز به ساخت جداگانه کتابخانه دارد.
  • فقط برای کارهایی که نیاز به عملکرد بالا دارند از NDK استفاده کنید: بازی‌ها، صدا، گرافیک، رمزنگاری، یادگیری ماشین روی دستگاه.
  • Google Play از تقسیم ABI از طریق App Bundle پشتیبانی می‌کند: کاربر فقط کتابخانه متناسب با معماری دستگاه خود را دریافت می‌کند.
  • کتابخانه‌های بومی APK را به طور قابل توجهی افزایش می‌دهند، اما حداکثر عملکرد و تأخیر کم را برای عملیات حیاتی فراهم می‌کنند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید