Как начать работу с Native Development Kit от Android
() translation by (you can also view the original English article)
С запуском Android Studio 2.2 разработка приложений для Android, содержащих код на C ++, стала проще, чем когда-либо. В этом уроке я покажу вам, как использовать набор Native Development Kit для Android, который обычно называют NDK, для создания собственной библиотеки C ++, функции которой доступны для классов Java.
Предпосылки
Чтобы иметь возможность следовать этому руководству, вам понадобится следующее:
- последняя версия Android Studio
- базовое понимание синтаксиса C ++
1. Зачем писать собственный код?
Как правило, вы должны разработать приложение для Android, используя только Java. Добавление кода на C ++ значительно увеличивает его сложность и снижает его переносимость. Тем не менее, вот несколько причин, по которым вы все равно хотите это сделать:
- Чтобы максимизировать производительность: вы можете повысить производительность приложения для Android, хотя и незначительно, путем внедрения части бизнес-логики на процессоре на C ++.
- Для использования высокопроизводительных API-интерфейсов: реализация спецификаций API, таких как Vulkan Graphics и OpenSL ES, является частью NDK. Поэтому разработчики Android-игр, как правило, используют NDK.
- Использовать популярные библиотеки C / C ++: существует множество библиотек C и C ++, которые не имеют эквивалентов Java. Если вы хотите работать с ними в своем приложении для Android, использование NDK - это ваше решение.
- Повторное использование кода: до тех пор, пока код, написанный на C ++, не содержит зависимостей от конкретной платформы, он может использоваться как в приложениях Android, так и в iOS, как правило, с минимальными изменениями. Если вы разрабатываете большое приложение и собираетесь поддерживать как платформы iOS, так и Android, использование C ++ может повысить вашу производительность.
2. Создание нового проекта
В Android Studio 2.2 или выше мастер создания проектов позволяет быстро создавать новые проекты, поддерживающие код на C ++.
Начните с запуска Android Studio и нажмите кнопку Start a new Android Studio project на экране приветствия. На следующем экране дайте вашему приложению осмысленное имя и проверьте поле Include C ++ Support.



На экране создания активности мастера выберите параметр Add No Activity. На последнем экране мастера убедитесь, что для значения поля C ++ Standard установлено значение Toolchain Default и нажмите кнопку Finish.



Android NDK и инструменты, от которых он зависит, по умолчанию не установлены. Поэтому, как только проект будет сгенерирован, вы увидите ошибку, которая выглядит так:



Чтобы исправить ошибку, откройте Tools > Android > SDK Manager и перейдите на вкладку SDK Tools.
В списке доступных инструментов разработчика выберите CMake и NDK и нажмите кнопку Apply.



После завершения установки перезапустите Android Studio.
3. Создание собственной библиотеки
Проект Android Studio, который поддерживает C ++, имеет дополнительный каталог исходного кода cpp. Как вы могли догадаться, все файлы и библиотеки C ++ должны быть размещены внутри него. По умолчанию в каталоге есть файл native-lib.cpp. Пока что мы напишем весь наш код на C ++ внутри него.
В этом уроке мы создадим простую нативную библиотеку, содержащую функцию, которая вычисляет площадь круга с помощью формулы πr². Функция примет радиус круга как jdouble
и вернет площадь как jstring
.
Начните с добавления в файл директив include
:
1 |
#include <jni.h> |
2 |
#include <string> |
3 |
#include <math.h> |
jni.h - это заголовочный файл, содержащий несколько макроопределений, типов, структур и функций, которые незаменимы при работе с NDK. (JNI означает Java Native Interface, и это среда, которая позволяет Java Runtime взаимодействовать с собственным кодом.) Заголовочный файл string необходим, потому что мы будем использовать тип jstring
в нашей библиотеке. Заголовочный файл math.h содержит значение π.
По умолчанию для поддержки полиморфизма компилятор C ++ модифицирует имена всех функций, которые вы определяете в своем коде. Эта функция часто упоминается как изменение имени. Из-за манипуляции с именем вызов ваших функций C ++ из кода Java приведет к ошибкам. Чтобы избежать ошибок, вы можете отключить управление именами, указав свои функции внутри блока extern "C"
.
1 |
extern "C" { |
2 |
// Your functions must be defined
|
3 |
// here
|
4 |
}
|
Имена функций C ++, доступные через JNI, должны иметь следующий формат:
- Они должны иметь префикс Java_.
- Они должны содержать искаженную форму имени пакета, где точки заменяются символами подчеркивания.
- Они должны содержать имя класса Java, к которому они принадлежат.
Кроме того, вы должны указать видимость функции. Вы можете сделать это, используя макрос JNIEXPORT.
По соглашению, большинство разработчиков также включают макрос JNICALL
в определении функции, хотя в настоящее время он не служит никакой цели в Android.
Следующий код определяет функцию, называемую calculateArea
, к которой можно получить доступ из класса Java, называемого MainActivity
:
1 |
JNIEXPORT jstring JNICALL |
2 |
Java_com_tutsplus_mynativeapplication_MainActivity_calculateArea( |
3 |
JNIEnv *jenv, |
4 |
jobject self, |
5 |
jdouble radius |
6 |
) { |
7 |
|
8 |
}
|
Обратите внимание, что помимо радиуса функция также принимает тип JNIEnv
, который имеет функции утилиты, которые вы можете использовать для обработки типов Java, и экземпляр jobject
, который является ссылкой на экземпляр MainActivity
. Мы, конечно, будем создавать MainActivity
позже в этом уроке.
Вычисление площади очень просто. Все, что вам нужно сделать, это умножить макрос M_PI
на квадрат radius
.
1 |
jdouble area = M_PI * radius * radius; |
Просто чтобы вы знали, как обрабатывать строки при работе с JNI, давайте теперь создадим новую строку, содержащую сообщение о том, что такое площадь. Для этого вы можете использовать функцию sprintf()
.
1 |
char output[40]; |
2 |
sprintf(output, "The area is %f sqm", area); |
Поскольку Java не может напрямую обрабатывать массив символов C ++, возвращаемый тип нашей функции - jstring
. Чтобы преобразовать массив output
в объект jstring
, вы должны использовать функцию NewStringUTF()
.
1 |
return jenv->NewStringUTF(output); |
На этом этапе наш код на C ++ готов.
4. Использование нативной библиотеки
На предыдущем шаге вы видели, что функция calculateArea()
должна принадлежать классу Java MainActivity
. Начните создавать класс, щелкнув правой кнопкой мыши имя вашего Java-пакета и выбрав File > New > Empty Activity.
В появившемся диалоговом окне назовите действие MainActivity. Убедившись, что опция Launcher Activity отмечена, нажмите кнопку Finish.



Перед тем, как его можно будет использовать, необходимо загрузить собственную библиотеку. Поэтому добавьте в класс static
блок и загрузите библиотеку с помощью метода loadLibrary()
класса System
.
1 |
static { |
2 |
System.loadLibrary("native-lib"); |
3 |
}
|
Чтобы иметь возможность использовать С++ функцию calculateArea()
внутри действия, вы должны объявить ее как native
метод.
1 |
private native String calculateArea(double radius); |
Теперь вы можете использовать метод calculateArea()
, как любой обычный метод Java. Например, вы можете добавить следующий код к методу onCreate()
для вычисления и печати области круга с радиусом 5,5:
1 |
Log.d(TAG, calculateArea(5.5f)); |
Если вы запустите приложение, вы сможете увидеть следующий вывод в окне logcat:



Заключение
В этом уроке вы узнали, как создать собственную C ++-библиотеку и использовать ее в приложении для Android. Стоит отметить, что собственный процесс сборки по умолчанию генерирует отдельный .so-файл для каждой архитектуры процессора, поддерживаемой NDK. Поэтому вы можете быть уверены, что ваше приложение будет работать на большинстве Android-устройств без каких-либо проблем.
Чтобы узнать больше об Android NDK, я предлагаю вам обратиться к руководству NDK.
И ознакомьтесь с некоторыми нашими другими учебниками и курсами по разработке Android!