Как разрабатывать Android‑приложения на C/C++ в 2026
Короткий ответ: в 2026 для высокопроизводительных модулей используют NDK r27+ (compileSdk 36) и связку Gradle + CMake; альтернативой C++ становится Rust через cargo‑ndk. Ниже — практическая настройка, пример и рекомендации для запуска нативного кода в Kotlin/Compose.
Быстрая настройка и интеграция NDK с SDK
- Установите NDK и инструменты:
- sdkmanager "ndk;27.0.12077973"
- Убедитесь, что у вас Android Gradle Plugin и Gradle 8.7+.
- В модуле app (build.gradle.kts) укажите:
android {
compileSdk = 36
ndkVersion = "27.0.12077973"
externalNativeBuild {
cmake {
path = "src/main/cpp/CMakeLists.txt"
version = "3.28"
}
}
defaultConfig {
externalNativeBuild {
cmake { cppFlags = "-std=c++17" }
}
ndk {
abiFilters += listOf("arm64-v8a","armeabi-v7a","x86_64")
}
}
}
- Простой C++ JNI‑функция (src/main/cpp/native-lib.cpp):
#include <jni.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainActivity_stringFromJNI(JNIEnv* env, jobject) {
return env->NewStringUTF("Hello from C++ NDK 2026!");
}
Kotlin:
class MainActivity : ComponentActivity() {
private external fun stringFromJNI(): String
companion object { init { System.loadLibrary("native-lib") } }
}
- Сборка: ./gradlew assembleDebug — в APK появится libnative-lib.so для указанных ABI.
Если планируете безопасную логику — рассмотрите Rust через cargo-ndk: он генерирует .so и сокращает риски ошибок памяти.
Пример проекта: OpenGL‑рендерер в Compose
Структура: app/src/main/cpp/{CMakeLists.txt, gl-renderer.cpp, gl-renderer.h} Основные шаги:
- CMake: подключите GLESv3 и log.
cmake_minimum_required(VERSION 3.28)
add_library(gl-renderer SHARED gl-renderer.cpp)
find_library(log-lib log)
target_link_libraries(gl-renderer ${log-lib} GLESv3 EGL)
- В gl-renderer.cpp реализуйте JNI‑методы init(width,height), drawFrame().
- В Kotlin используйте AndroidView/GlSurfaceView или NativeComposeInterop для рендера в Compose, создайте хук на lifecycle для вызова native init/draw.
Реальные оптимизации: используйте precompiled shaders, VBO/VAO, минимизируйте переключения state, профилируйте GPU.
Не создавайте std::thread внутри UI‑потока без синхронизации. Для JNI‑вызовов предпочитайте корутины, HandlerThread или native task queues.
Сравнение C++ и Rust (когда выбирать)
- C++: максимум экосистемы (игры, существующий код), оптимизации LLVM.
- Rust: почти та же производительность, значительно выше безопасность памяти — хорош для новых ML/приложений и критичных модулей.
- Выбор: перенос legacy/Unity/Unreal — C++; новая критичная логика — Rust.
Частые ошибки
- Неправильный ndkVersion в Gradle → сборка использует другой NDK.
- Забыт System.loadLibrary(...) или несоответствие имени библиотеки.
- Выставлены неправильные abiFilters — отсутствуют нужные .so в APK.
- Использование blocking IO/threads в UI без синхронизации → ANR/краши.
- Несоответствие compileSdk и используемых фич (Compose NativeInterop требует compileSdk 36+).
FAQ
- Нужно ли использовать NDK для простых приложений? Нет — только для критичных по производительности модулей.
- Как тестировать нативный код? Используйте Android Studio Profiler + perfetto и аппаратные профайлеры; эмулятор полезен, но тестируйте на реальных устройствах с нужной архитектурой.
- Можно ли смешивать C++ и Rust в одном модуле? Да — Rust может экспортировать C ABI, затем подключать через C++/JNI.
Лучшие практики: профилируйте CPU/GPU, минимизируйте переходы между Java/Kotlin и native, покрывайте ключевые нативные участки тестами, автоматизируйте сборку через AGP + CMake/cargo‑ndk.