Разработчик: Усачёв Денис Евгеньевич, ведущий эксперт РыбинскЛАБ
Зачем делать NDK в Termux
Termux — мощная среда для работы в оболочке на Android. При наличии корректно собранного toolchain и понятной связки с Android-проектом (Gradle/ABI/Manifest) можно организовать разработку и отладку нативных модулей так же системно, как на Linux. Ниже — практический путь: от подготовки до сборки, линковки и отладки.
Ограничения и важные замечания
- Архитектуры (ABI): NDK-сборка зависит от ABI (arm64-v8a, armeabi-v7a, x86_64 и т.д.). Подбирайте целевую архитектуру под устройство.
- Платформенная интеграция: для загрузки .so в Android-приложении нужен Java/Kotlin-контур и корректная конфигурация проекта (lib + System.loadLibrary).
- Отладка: полноценная отладка (breakpoints, step) обычно требует связки с Android Studio/LLDB. Но базовую верификацию можно делать прямо через logcat и тестовые вызовы.
- Никаких обходов блокировок через VPN: если вы используете VPN, то только для создания локальной сети (например, для лабораторного стенда), не для обхода ограничений.
Подготовка окружения Termux
Начните с обновления пакетов и установки базовых инструментов. Мы будем использовать кросс-компиляцию под Android из Termux.
pkg update -y
pkg upgrade -y
pkg install -y clang lld make cmake ninja git curl unzip tar
Дальше важно получить NDK. Есть два типовых подхода:
- Вариант A (рекомендуется): использовать NDK, скачанный/встроенный в ваш Android Studio-проект.
- Вариант B: вручную скачать NDK и использовать его напрямую из Termux (потребуются аккуратные пути и версии).
Для согласованности с Android-проектом рассмотрим Вариант A, но решения в целом применимы и к B.
Структура проекта: как связать NDK и Termux
Схема обычно такая:
- Termux — сборка нативной части (C/C++), генерация .so.
- Android-приложение — размещение .so по ABI, загрузка библиотек и вызов нативных функций.
Минимальная структура:
your-android-app/
app/
src/main/
java/... (Kotlin/Java)
jniLibs/
arm64-v8a/
libnative-lib.so
armeabi-v7a/
libnative-lib.so
(или src/main/jni/ + Gradle сборка, но вы идёте через Termux)
Если вы хотите “полный цикл” именно в Termux, то удобнее собирать .so вручную и класть готовые артефакты в src/main/jniLibs/<abi>.
Получение путей к NDK и toolchain
Обычно NDK хранится в каталоге Android Studio или в папке проекта. Например, внутри Gradle можно найти путь к NDK.
В Termux вам понадобятся:
- путь к
$ANDROID_NDK - выбранный
$ABI - API level (минимальный Android API)
Пример установки переменных окружения (пути подставьте под ваш проект):
export ANDROID_NDK=/path/to/your-ndk
export ABI=arm64-v8a
export ANDROID_PLATFORM=android-24
Сборка нативной библиотеки: компиляция и линковка
Рассмотрим минимальный пример C++ библиотеки, которую мы соберём в .so. Предположим, что исходники находятся в каталоге native/ в вашем проекте.
native/native-lib.cpp:
#include <jni.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(JNIEnv env, jobject / this */) {
return env->NewStringUTF("Hello from native (built in Termux)");
}
Далее — сборка. Ключевой момент: использовать правильный компилятор из NDK и правильные флаги для линковки.
Ниже — “ручная” схема (подходит для базовой библиотечной сборки). Пример для arm64-v8a:
# Переходим в каталог с исходниками (подстройте пути)
cd /path/to/your-android-app/app/src/main/native
# Определяем toolchain prefix
TOOLCHAIN="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android"
# Если среда prebuilt отличается (например, darwin), подстройте linux-x86_64.
# Компиляция
$TOOLCHAIN$ANDROID_PLATFORM-clang++ \
-fPIC \
-std=c++17 \
-O2 \
-c native-lib.cpp \
-o native-lib.o
# Линковка в .so
$TOOLCHAIN$ANDROID_PLATFORM-clang++ \
-shared \
-Wl,--no-undefined \
native-lib.o \
-o /path/to/your-android-app/app/src/main/jniLibs/arm64-v8a/libnative-lib.so
Важно: путь к prebuilt/linux-x86_64 зависит от вашей хост-платформы, но в Termux “хостом” физически остаётся ваше Android-устройство. Поэтому этот вариант применим, если вы используете NDK-архив, содержащий prebuilt под нужную систему, либо заранее корректно разместили NDK. На практике чаще “безболезненнее” опираться на Gradle, но вы просите именно Termux-циклы — тогда внимательно проверьте реальный путь к компилятору в вашем NDK.
Проверка артефактов: права, ABI и символы
После линковки убедитесь, что .so действительно собрана под нужный ABI. Для первичной проверки можно использовать утилиты из NDK/бинари.
# Пример проверки (инструменты могут называться по-разному)
ls -lah /path/to/your-android-app/app/src/main/jniLibs/arm64-v8a/libnative-lib.so
# Если доступны readelf/llvm-readobj:
# readelf -h libnative-lib.so | head
Также убедитесь, что имя библиотеки соответствует тому, что будет грузиться в Android-коде: например, libnative-lib.so соответствует System.loadLibrary("native-lib").
Интеграция в Android-проект (Kotlin/Java) и загрузка .so
В MainActivity (или другом классе) объявите native-метод и загрузите библиотеку.
Пример Kotlin:
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("native-lib")
}
}
external fun stringFromJNI(): String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tv = findViewById<TextView>(R.id.textView)
tv.text = stringFromJNI()
}
}
Если подписи JNI не совпадут, метод не найдёт корректную реализацию. Поэтому проверьте пакет/имя класса и сигнатуру (как в C++ функции Java_..._... соответствуют имени пакета и классу).
Сборка и запуск приложения после Termux-сборки
Далее вы собираете APK/AAB стандартным способом (Gradle). Варианты:
- в Android Studio (быстрее для отладки)
- через Gradle из Termux при наличии подходящей JVM/Gradle (обычно удобнее всё же через Android Studio)
На практике чаще делается так: вы собираете .so в Termux, затем запускаете приложение через Android Studio, которая подхватит обновлённый файл в jniLibs.
Отладка: logcat, проверки JNI и подготовка к LLDB
Базовая диагностика обычно начинается с logcat.
adb logcat | grep -i native
Если у вас есть отладочные сообщения в native-коде — используйте Android logging (через android_log_print), но это потребует подключения android/log.h и линковки к log библиотеке.
Пример добавления логов:
#include <android/log.h>
#define LOG_TAG "native-lib"
android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Value=%d", value);
И затем при линковке иногда нужно добавить -llog (зависит от архитектуры и точных флагов).
Отладка с символами и ожидания отладчика
Для более комфортной отладки убедитесь, что линковка включает отладочную информацию. Вместо -O2 используйте -O0 -g на время отладки.
# Временно для отладки
$TOOLCHAIN$ANDROID_PLATFORM-clang++ \
-fPIC -std=c++17 \
-O0 -g \
-c native-lib.cpp -o native-lib.o
$TOOLCHAIN$ANDROID_PLATFORM-clang++ \
-shared \
-Wl,--no-undefined \
-g \
native-lib.o \
-o /path/to/your-android-app/app/src/main/jniLibs/arm64-v8a/libnative-lib.so
Для работы с точками останова и пошагового выполнения обычно требуется подключение отладчика (LLDB) через Android Studio. Однако сам факт наличия корректных symbol files (-g) и единообразных путей сильно помогает.
Рекомендованный “workflow” для ежедневной разработки
- Шаг 1: Изменили C/C++ в
native/. - Шаг 2: Собрали .so в Termux (компиляция + линковка с нужными флагами).
- Шаг 3: Запустили/перезапустили приложение в Android Studio.
- Шаг 4: Проверили поведение через UI и logcat.
- Шаг 5: При необходимости включили
-O0 -gи перешли к более “серьёзной” отладке.
Типичные проблемы и как их устранить
- UnsatisfiedLinkError: библиотека не загрузилась или имя/пакет JNI не совпали.
- Проблемы ABI: приложение ищет .so под конкретную архитектуру устройства. Убедитесь, что нужный ABI есть в
jniLibs. - Проблемы с JNI-именами: проверьте соответствие функции:
Java_<package>_<Class>_<method>и сигнатуры. - Некорректный NDK toolchain путь: проверьте реальный путь к
clang++внутри NDK.
Заключение
Разработка и отладка нативных Android‑модулей (NDK) прямо в Termux возможна и практична при правильной настройке: точные пути к NDK, дисциплина по ABI, аккуратная компиляция/линейка в .so и понятная интеграция через jniLibs + System.loadLibrary. Для отладки эффективно комбинируйте Termux-сборку (с отладочными символами) и Android-диагностику через logcat и инструменты IDE.
Если вам нужна помощь с настройкой окружения, переносом проекта на “Termux-first workflow”, отладкой JNI/ABI или выстраиванием CI для нативной сборки — обращайтесь в РыбинскЛАБ. Мы поможем довести процесс до стабильного промышленного уровня.