Создание приложения Android Native Activity
После установки кроссплатформенной рабочей нагрузки Разработка мобильных приложений на языке C++ Visual Studio можно использовать для создания полнофункциональных приложений Android Native Activity. Пакет Android Native Development Kit (NDK) — это набор средств, с помощью которых можно реализовывать большинство возможностей приложения Android, используя чистый код C или C++. Для обеспечения взаимодействия кода C или C++ с Android используется определенный код Java JNI, выступающий в роли связующего. В Android NDK появилась возможность создавать приложения Native Activity с помощью API Android уровня 9. Код Native Activity популярен для создания игровых приложений и приложений с интенсивным использованием графики на основе Unreal Engine или OpenGL. В этом пошаговом руководстве показано создание простого приложения Native Activity, в котором используется OpenGL. В дополнительных разделах последовательно рассматриваются такие этапы жизненного цикла разработки, как редактирование, сборка, отладка и развертывание кода Native Activity.
Требования
Прежде чем создавать приложение Android Native Activity, необходимо убедиться, что вы выполнили все системные требования и установили рабочую нагрузку Разработка мобильных приложений на языке C++ в Visual Studio. Дополнительные сведения см. в статье Установка Visual C++ для разработки кроссплатформенных мобильных приложений на языке C++. Убедитесь, что необходимые сторонние инструменты и пакеты SDK включены в установку, а также что установлен эмулятор Android.
Создание проекта Native Activity
В этом руководстве вы сначала создадите новый проект Android Native Activity, а затем создадите и запустите приложение по умолчанию в эмуляторе Android.
- В Visual Studio выберите Файл>Создать>Проект.
- В диалоговом окне Новый проект в меню Шаблоны последовательно выберите Visual C++>Кроссплатформенное приложение, а затем выберите шаблон Приложение Native-Activity (Android).
- Присвойте приложению имя, например MyAndroidApp, а затем нажмите OK.
Visual Studio создаст новое решение и откроет обозреватель решений. 
- В Visual Studio выберите Файл>Создать>Проект.
- В диалоговом окне Создание нового проекта выберите шаблон Приложение Native-Activity (Android), а затем нажмите Далее.
- В диалоговом окне Настроить новый проект введите имя, например MyAndroidApp в разделе Имя проекта, а затем выберите Создать. Visual Studio создаст новое решение и откроет обозреватель решений.
В новое решение приложения Android Native Activity входят два проекта.
- MyAndroidApp.NativeActivity содержит ссылки и связующий код для запуска приложения как приложения Native Activity на Android. Реализация точек входа из связующего кода находится в файле main.cpp. Предкомпилированные заголовки находятся в файле pch.h. Этот проект приложения Native Activity компилируется в общую библиотеку (файл SO), которая передается в проект упаковки.
- MyAndroidApp.Packaging создает файл с расширением .apk для развертывания на устройстве или в эмуляторе Android. Он содержит ресурсы и файл AndroidManifest.xml, в котором задаются свойства манифеста. В него также входит файл build.xml, управляющий процессом сборки Ant. По умолчанию он задан как начальный проект, который можно развернуть и запустить непосредственно из Visual Studio.
Создание и запуск приложения Android Native Activity по умолчанию
Разработайте и запустите приложение, созданное шаблоном, чтобы проверить установку и настройку. Для первоначального теста запустите приложение в одном из профилей устройств, установленных эмулятором Android. Если вы предпочитаете тестировать приложение на другой платформе, загрузите целевой эмулятор или подключите устройство к компьютеру.
Сборка и запуск приложения Native Activity по умолчанию
- Выберите пункт x86 из раскрывающегося списка Платформы решения , если он еще не выбран.
Если список Платформы решения не отображается, щелкните пункт Платформы решения из раскрывающегося списка Добавить или удалить кнопки и выберите свою платформу. - В строке меню последовательно выберите Сборка>Собрать решение. В окне «Выходные данные» отобразятся выходные данные процесса сборки для двух проектов в решении.
- Выберите один из профилей эмулятора Android в качестве цели развертывания. Если вы установили другие эмуляторы или подключили устройство Android, то можете выбрать их в раскрывающемся списке платформы развертывания.
- Нажмите F5, чтобы начать отладку, или Shift+F5 для запуска без отладки. Вот как выглядит приложение по умолчанию в эмуляторе Android.
Visual Studio запускает эмулятор, который за несколько секунд загружает и развертывает код. После запуска приложения можно задать точки останова и использовать отладчик для проверки кода, языковых стандартов и контрольных значений. - Для остановки отладки нажмите SHIFT+F5. Эмулятор является отдельным процессом, который продолжает выполняться. Вы можете изменять, компилировать и развертывать код несколько раз в одном эмуляторе.
Android NDK
«Хотя это и позволяет писать нативные приложения, работающие быстрее чем Java, писать только на C/C++ нельзя, точка входа обязательно должна быть написана на Java», — это не правда. Полностью нативные андроид-приложения можно делать чуть ли не со времён 9-й версии API (android 2.3). Proof: https://developer.android.com/ndk/samples/sample_na
#2
19:07, 24 фев 2021
General GDA
Пофиксил
- General GDA
- Постоялец
#3
19:50, 24 фев 2021
Я бы ещё текст прогнал через спелл чекер (пунктуация, опечатки) и согласовал предложение. А то «это . » и начинается с маленькой буквы, и читается как-то не очень. Но это мелочи.
Главное, что «работающие быстрее, чем Java», — это субъективное оценочное суждение. Мало того, что на android нету Java (да, программу на этом языке можно скомпилировать для работы на Android; но на устройствах нет Java VM, модель памяти отличается от Java и т.п.). Так ещё на C/C++ надо постараться написать быстрее. К примеру, в современных андроидах очень сложная среда исполнения, где есть пред-компиляция в нативный код ещё на момент инсталляции приложения. При обновлении ОС может (и делает) перекомпиляция такого кода. Ещё пример: лично я при должном старании определённый класс задач под андроид вполне могу написать на Java/Kotlin так, что будет быстрее, чем на C++. Как в плане скорости выполнения кода, так и в плане скорости его написания.
Раз форум у нас тут гемдеву посвящён. То я могу набросить пример: на Unity так вообще всё на C# пишется. И ничего. Тонны успешных проектов (гемдев проектов!) под мобильные телефоны.
Если и писать про «быстрее», то со ссылками на конкретные исследования или case studies.
#4
13:12, 25 фев 2021
General GDA, хотелось бы поподробнее, как вы напишите приложение, которое написано на Java так, чтобы оно работало быстрее внутреннего цикла нативной программы? В плане скорости работы кода.
Про скорость написания — это зависит от того, что уже для этого сделано.
#5
15:50, 25 фев 2021
Mirrel
ну, как пример из головы — если работа приложения состоит в обработке строк или структур, которые оно получает с помощью одних вызовов API и отображает с помощью других, то большую часть времени нативное приложение может заниматься перепаковыванием их в свое представление, а java — будет работать с данными «как есть».
Другой пример — оптимизатор java вполне может быть круче оптимизатора fpc и соответственно одни и те же вычисления будут преобразованы в более эффективный машинный код.
#6
18:23, 25 фев 2021
kipar, я не об этом спрашивал!
Есть (у абсолютно нативного приложения) свой внутренний цикл (как и в других системах). Из этого цикла и происходят всё вызовы этого самого приложения (Start, Stop, Pause, Resume . ).
Как, человек сможет, используя java-код, обойти скорость работы внутреннего цикла?
И, всеми данными, можно пользоваться из нативного кода. В дополнению к этому, многие данные на Android находятся именно в нативном виде, а внутренние библиотеки соединяют этот код для удобства работы с Java-кодом.
но это больше для информации.
#7
18:43, 25 фев 2021
Mirrel
> Start, Stop, Pause, Resume
эти операции делаются достаточно редко, чтобы игнорировать JNI-оверхед при их вызове. Да даже если Update — один JNI-вызов каждый кадр — это копейки.
#8
18:45, 25 фев 2021
Что если, я скажу, что можно полностью игнорировать JNI-вызовы?
#9
18:51, 25 фев 2021
Mirrel
> Что если, я скажу, что можно полностью игнорировать JNI-вызовы?
и писать при этом на яве?
#10
19:41, 25 фев 2021
Зачем? Лично я буду писать на Паскале. Другой народ на C/C++. Кто умеет, тот на каком ещё языке, кроме всех вышеперечисленных.
#11
22:46, 25 фев 2021
General GDA
То есть dalvik и art не выполняют (свой) java байт-код? Про скорость C/C++ согласен.
оффтоп: как цитаты писать?
#12
23:31, 25 фев 2021
egoros7
Dalvik, вроде как — вполне себе jvm и исполняет байткод. Хотя и не совсем compliant. А art — он AOT.
#13
23:38, 25 фев 2021
kkolyan
>а art — он AOT
Ну при включении машинный код всё же компилируется из байт-кода. Или я не прав?
#14
23:41, 25 фев 2021
egoros7
Скорее всего да, т.к. это проще чем компилить из сорцов. Но я наверняка не знаю.
Учимся работать с Android NDK или как использовать C код в java проектах

Android NDK представляет собой набор утилит, позволяющих Вам включать код, написанный на C и C++, в ваше приложение. Такой код называется нативным(native), поскольку он не может быть выполнен на виртуальной машине и компилируется непосредственно в машинный код требуемой процессорной архитектуры.
Данный урок относится к разряду продвинутых. Подразумевается, что читатель уже имеет некоторые навыки, в частности
- Вы умеете программировать на Java и C
- Вы умеете работать с командной строкой
- Вы знаете, как узнать версии Cygwin, awk и других инструментов, которыми нам придется пользоваться
- Вы умеете разрабатывать приложения для Android
- У Вас настроена среда разработки для Android (в момент написания автор использовал Android 2.2)
- Вы используете Eclipse или можете транслировать инструкции по работе с eclipse на свою IDE.
Если какой-либо из указанных пунктов вызывает у вас затруднения, не беда, вы все равно вполне можете усвоить предлагаемый материал, правда некоторые шаги будут казаться Вам довольно сложными. Вообще вопрос использование Android NDK часто вызывает затруднения даже у матерых разработчиков. Скорей всего вам придется приложить значительные усилия, прежде чем вы сможете настроить свою среду разработки и написать работающий проект.
Когда нужно использовать Android NDK?
Обычно разработчики решают использовать нативный код в двух случаях: они хотят увеличить производительность своего приложения, или у них есть готовый C/C++ проект, который требуется с минимальными затратами портировать на Android. Давайте не будем спешить и разберемся, когда же целесообразно использовать NDK, а когда этого не нужно делать.
Наиболее часто программистами высказывается мнение, что NDK стоит использовать, когда приложение сильно нагружает процессор. Существуют алгоритмы, позволяющие полностью загрузить процессор через DalvikVM, в этом случае использование нативного кода действительно с большой вероятностью позволит получить выигрыш в производительности. Однако, не нужно забывать, что использование JIT компилятора также позволяет повысить производительность java кода. Многие думают, что использование в приложении машинного кода автоматически означает увеличение скорости работы приложения. На самом деле это не так. Переключение с выполнения java кода на машинный код и обратно несет с собой накладные расходы, поэтому использовать NDK стоит, только если у вас выполняется какой-нибудь долгий сложный расчет, полностью написанный на C, и в java коде не предполагается частое дерганье нативных функций.
Другой причиной, которая может побудить Вас использовать NDK является необходимость портирования готового приложения. Вполне логично не переписывать уже проверенные и отлаженные куски кода на java, а использовать NDK. Этот подход также позволит Вам в дальнейшем без особых затрат вносить параллельно правки в исходное и портированное на android приложение. В частности, такой подход оправдан в отношении приложений, использующих OpenGL ES.
Шаг 1: Установка Android NDK и настройка среды разработки
Прежде всего, Вам необходимо скачатьAndroid NDK. Для установки и нормальной работы нам также понадобятся утилиты Cygwin 1.7 или старше, awk последней версии, а также GNU Make 3.81 или старше.
После того, как Вы скачали архив с NDK, распакуйте его в какую-нибудь папку. Можно распаковать этот архив туда же, где лежит Android SDK. Путь к этой папке необходимо прописать в системной переменной PATH. В Windows для этих целей лучше настроить конфигурацию Cygwin.
Шаг 2: Создание нового проекта
Создайте новый Android проект. Чтобы избежать проблем в будущем сохраните проект так, чтобы путь к нему не содержал в себе символов пробела. Для примера создайте проект, в качестве названия пакета укажите «com.mamlambo.sample.ndk1», а в качестве Activity — «AndroidNDK1SampleActivity».
В корне проекта создайте папку с названием «jni». Именно здесь будет содержаться файлы с нативным кодом. Если Вы знакомы с JNI, то вам будет приятно узнать, что Android NDK по сути представляет собой JNI с ограниченным набором заголовочных файлов для компиляции C кода.
Шаг 3: Добавляем C код в Android проект
Создайте в папке jni файл с именем native.c и добавьте в него следующий код
#include #include #include #define DEBUG_TAG "NDK_AndroidNDK1SampleActivity" void Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_helloLog(JNIEnv* env, jobject this, jstring logThis) { jboolean isCopy; const char* szLogThis=(*env)->GetStringUTFChars(env, logThis,&isCopy); __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG,"NDK:LC: [%s]", szLogThis); (*env)->ReleaseStringUTFChars(env, logThis, szLogThis); }
Созданная таким образом функция берет параметр String у java объекта, конвертирует его в C-string и записывает в LogCat. Зубодробительное имя функции выбрано не случайно, оно несет в себе важную информацию: сначала указывается название паттерна («Java»), затем идут название пакета, имя класса и название метода. Каждая часть имени отделяется знаком подчеркивания.
Первые два параметра у функции имеют особое значение. Первый параметр определяет JNI среду и часто используется со вспомогательными функциями. Второй параметр является объектом Java, частью которого является функция.
Шаг 4: Вызов нативного кода из Java
Давайте создадим в нашем проекте кнопку, при нажатии на которую будем вызывать следующий код:
helloLog("This will log to LogCat via the native call.");
Необходимо также объявить функцию helloLog в классе, где она вызывается. Сделать можно с помощью строки
private native void helloLog(String logThis);
Таким образом, мы сообщаем компилятору и линковщику, что реализацию этой функции стоит искать в папке с нативным кодом.
Наконец, нужно загрузить библиотеку, куда в конечном счете будет скомпилирован код. Добавьте следующую инициализацию в класс Activity.
static{ System.loadLibrary("ndk1"); }
System.loadLibrary() обеспечивает загрузку библиотеки по имени. Вы можете использовать любое название.
Шаг 5: Создаем Make file для нативного кода
Для компиляции нативного кода в папке jni должен находиться Make file с именем «Android.mk». Ниже приведен код этого фала для нашего примера, то есть когда функция находится в файле native.c и в качестве имени библиотеки указано ndk1
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := ndk1
LOCAL_SRC_FILES := native.c
include $(BUILD_SHARED_LIBRARY)
Шаг 6: компиляция нативного кода
После того, как Вы написали код и добавили make файл в папку jni можно приступать к компиляции. Для этого нужно в командной строке (Если вы работаете в windows, запустите Cygwin) запустить ndk-build из папки проекта. Утилита ndk-build входит в состав Android NDK. Если Вы все сделали правильно, то вы должны увидеть что-то вроде этого

Шаг 7: Запуск приложения
Теперь можно запустить проект, нажать на кнопку и посмотреть, как изменится LogCat.
Может произойти одна из двух вещей: 1) ваш проект может запуститься и работать, как Вы того ожидаете. В этом случае примите мои поздравления. 2) Возникнет ошибка, которая в LogCat отобразиться как «Could not execute method of activity.» Ничего страшного. Обычно Eclipse сконфигурирован так, что при запуске проекта автоматически происходит его перекомпиляция. В случае, если эта опция отключена, то нужно вручную заставить Eclips перекомпилировать проект. Для этого перед запуском нужно вызвать менюProject->Clean from the Eclipse toolbar.
Шаг 8: Как вернуть объект из нативной функции
Следующий пример демонстрирует возможность нативных функций возвращать объекты, например String. Добавьте код в файл native.c
jstring Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_getString(JNIEnv* env, jobject this, jint value1, jint value2) { char*szFormat="The sum of the two numbers is: %i"; char*szResult; // добавляем две переменные jlong sum= value1+value2; // malloc для строки результата szResult= malloc(sizeof(szFormat)+20); // standard sprintf sprintf(szResult, szFormat, sum); // получаем объект string jstring result=(*env)->NewStringUTF(env, szResult); // очищаем память free(szResult); return result; }
С помощью команды malloc мы создали буфер, куда затем с помощью sprintf поместили строку. Чтобы функция возвращала корректный результат, мы использовали JNI helper функцию NewStringUTF(), которая фактически создает Java объект на основании C строки. После этого мы очистили память с помощью команды free().
Для успешной компиляции проекта необходимо в native.c подключить заголовочный файл stdio.h. В классе Activity нужно также объявить новую функцию:
private native String getString(int value1, int value2);
после этого с функцией getString можно работать, например следующим образом:
String result= getString(5,2); Log.v(DEBUG_TAG,"Result: "+result); result= getString(105,1232); Log.v(DEBUG_TAG,"Result2: "+result);
Замечания
Android NDK для своей работы требует Android SDK 1.5. С помощью NDK можно получить доступ ко многим API, например к OpenGL ES.
Нативный код компилируется в машинный код, соответствующий архитектуре процессора, и поскольку на разных телефонах используются процессоры разной архитектуры, у Вас может возникнуть проблемы с переносимостью программы. По умолчанию NDK производит компиляцию для ARMv5TE. Когда Вы запускаете свое приложение на эмуляторе, а не на реальном устройстве, этот машинный код выполняется не напрямую, а через еще один эмулятор процессора.
Заключение
Ну вот собственно и все. Думаю теперь вам понятно, как работать с нативным кодом. Во многих случаях его применение оправдано, однако бездумное применеие нативного кода в своих проектах может оказаться губительным.
Авторы:Lauren Darcey и Shane Conder
Источник:Advanced Android: Getting Started with the NDK
Перевод:Александр Ледков
О метке
Android NDK (native development kit) – это набор инструментов, которые позволяют реализовать часть вашего приложения, используя такие языки как С/С++. Используйте данную метку, когда ваш проект связан с разработкой под Android на вышеупомянутых языках.
Android NDK (native development kit) — это набор инструментов, который позволяет использовать код С/C++ с Android и предоставляет библиотеки для платформы, которые вы можете использовать для управления собственными действиями и доступа к физическим компонентам устройства, таким как датчики и сенсоры. NDK может быть полезен для случаев, когда вам необходимо выполнить одно или несколько из следующих действий:
- для извлечения большей производительности из устройства для достижения низкой задержки или запуска приложений с ресурсоемкими вычислением, такие как игры или физическое моделирование
- для повторного использования собственных или других библиотек разработанных на языках C/C++.