Основные понятия

Прежде чем начать

В этом руководстве предполагается, что вы уже знакомы с концепциями, присущими нативному программированию и разработке под Android .

Введение

В этом разделе представлено общее объяснение того, как работает NDK. Android NDK — это набор инструментов, позволяющий встраивать C или C++ («собственный код») в ваши приложения Android. Возможность использовать собственный код в приложениях Android может быть особенно полезна для разработчиков, которые хотят выполнить одно или несколько из следующих действий:

  • Портируйте свои приложения между платформами.
  • Повторно используйте существующие библиотеки или предоставляйте собственные библиотеки для повторного использования.
  • Увеличьте производительность в определенных случаях, особенно в тех, которые требуют больших вычислительных ресурсов, например в играх.

Как это работает

В этом разделе представлены основные компоненты, используемые при создании собственного приложения для Android, а также описан процесс сборки и упаковки.

Основные компоненты

При создании приложения вы должны иметь представление о следующих компонентах:

  • Собственные общие библиотеки: NDK собирает эти библиотеки или файлы .so из исходного кода C/C++.

  • Собственные статические библиотеки: NDK также может создавать статические библиотеки или файлы .a , которые можно связать с другими библиотеками.

  • Собственный интерфейс Java (JNI): JNI — это интерфейс, через который компоненты Java и C++ взаимодействуют друг с другом. Это руководство предполагает знание JNI; информацию об этом можно найти в Спецификации собственного интерфейса Java .

  • Двоичный интерфейс приложения (ABI). ABI точно определяет, как машинный код вашего приложения будет взаимодействовать с системой во время выполнения. NDK создает файлы .so на основе этих определений. Разные ABI соответствуют разным архитектурам: NDK включает поддержку ABI для 32-разрядных ARM, AArch64, x86 и x86-64. Дополнительные сведения см. в разделе Android ABI .

  • Манифест. Если вы пишете приложение без компонента Java, вы должны объявить класс NativeActivity в манифесте . Дополнительные сведения о том, как это сделать, см. в разделе «Использование интерфейса Native_activity.h» .

Поток

Общий процесс разработки собственного приложения для Android выглядит следующим образом:

  1. Разработайте свое приложение, решив, какие части реализовать на Java, а какие — в машинном коде.

  2. Создайте проект приложения Android, как и любой другой проект Android.

  3. Если вы пишете только собственное приложение, объявите класс NativeActivity в AndroidManifest.xml . Дополнительные сведения см. в разделе «Нативные действия и приложения» .

  4. Создайте файл Android.mk , описывающий собственную библиотеку, включая имя, флаги, связанные библиотеки и исходные файлы, которые будут скомпилированы в каталоге «JNI».

  5. При желании вы можете создать файл Application.mk , настроив целевые ABI, цепочку инструментов, режим выпуска/отладки и STL. Для любого из них, которые вы не указали, используются соответственно следующие значения по умолчанию:

    • ABI: все неустаревшие ABI.
    • Режим: Релиз
    • СТЛ: система
  6. Поместите исходный код в каталог jni проекта.

  7. Используйте ndk-build для компиляции собственных библиотек ( .so , .a ).

  8. Создайте компонент Java, создав исполняемый файл .dex .

  9. Упакуйте все в APK-файл, содержащий .so , .dex и другие файлы, необходимые для запуска вашего приложения.

Нативные действия и приложения

Android SDK предоставляет вспомогательный класс NativeActivity , который позволяет вам писать полностью нативное действие. NativeActivity обрабатывает связь между платформой Android и вашим собственным кодом, поэтому вам не нужно создавать его подклассы или вызывать его методы. Все, что вам нужно сделать, это объявить ваше приложение нативным в файле AndroidManifest.xml и приступить к созданию нативного приложения.

Приложение Android, использующее NativeActivity, по-прежнему работает на собственной виртуальной машине, изолированной от других приложений. Таким образом, вы по-прежнему можете получить доступ к API платформы Android через JNI. В некоторых случаях, например, для датчиков, входных событий и ресурсов, NDK предоставляет собственные интерфейсы, которые можно использовать вместо вызова через JNI. Дополнительные сведения о такой поддержке см. в разделе Собственные API .

Независимо от того, разрабатываете ли вы собственное действие, мы рекомендуем вам создавать свои проекты с помощью традиционных инструментов сборки Android. Это помогает обеспечить создание и упаковку приложений Android с правильной структурой.

Android NDK предоставляет вам два варианта реализации вашей собственной активности:

  • Заголовок Native_activity.h определяет собственную версию класса NativeActivity . Он содержит интерфейс обратного вызова и структуры данных, необходимые для создания собственной активности. Поскольку основной поток вашего приложения обрабатывает обратные вызовы, ваши реализации обратного вызова не должны блокироваться. Если они блокируются, вы можете получить ошибки ANR (приложение не отвечает), поскольку ваш основной поток не отвечает до тех пор, пока не вернется обратный вызов.
  • Файл android_native_app_glue.h определяет статическую вспомогательную библиотеку, построенную на основе интерфейса Native_activity.h . Он порождает другой поток, который обрабатывает такие вещи, как обратные вызовы или события ввода в цикле событий. Перемещение этих событий в отдельный поток предотвращает блокировку основного потока любыми обратными вызовами.

Также доступен исходный код <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c , позволяющий изменить реализацию.

Для получения дополнительной информации о том, как использовать эту статическую библиотеку, изучите пример приложения с собственными действиями и его документацию. Дальнейшее чтение также доступно в комментариях в файле <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h .

Используйте интерфейс Native_activity.h

Чтобы реализовать собственное действие с помощью интерфейсаnative_activity.h :

  1. Создайте каталог jni/ в корневом каталоге вашего проекта. В этом каталоге хранится весь ваш собственный код.

  2. Объявите свою собственную активность в файле AndroidManifest.xml .

    Поскольку в вашем приложении нет кода Java, установите android:hasCode значение false .

    <application android:label="@string/app_name" android:hasCode="false">
    

    Для атрибута android:name тега активности необходимо установить значение NativeActivity .

    <activity android:name="android.app.NativeActivity"
              android:label="@string/app_name">
    

    Атрибут android:value тега meta-data указывает имя общей библиотеки, содержащей точку входа в приложение (например, C/C++ main ), опуская префикс lib и суффикс .so в имени библиотеки.

    <manifest>
      <application>
        <activity>
          <meta-data android:name="android.app.lib_name"
                     android:value="native-activity" />
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
      </application>
    </manifest>
    
  3. Создайте файл для своей собственной активности и реализуйте функцию, указанную в переменной ANativeActivity_onCreate . Приложение вызывает эту функцию при запуске собственного действия. Эта функция, аналогичная main в C/C++, получает указатель на структуру ANativeActivity , которая содержит указатели функций на различные реализации обратного вызова, которые вам нужно написать. Установите соответствующие указатели на функции обратного вызова в ANativeActivity->callbacks для реализации ваших обратных вызовов.

  4. Установите в поле ANativeActivity->instance адрес любого экземпляра конкретных данных, которые вы хотите использовать.

  5. Реализуйте все, что вы хотите, чтобы ваша деятельность выполнялась при запуске.

  6. Реализуйте остальные обратные вызовы, которые вы установили в ANativeActivity->callbacks . Дополнительные сведения о том, когда вызываются обратные вызовы, см. в разделе «Управление жизненным циклом активности» .

  7. Разработайте остальную часть вашего приложения.

  8. Создайте Android.mk file в каталоге jni/ вашего проекта, чтобы описать ваш собственный модуль для системы сборки. Для получения дополнительной информации см. Android.mk .

  9. Получив файл Android.mk , скомпилируйте собственный код с помощью команды ndk-build .

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. Создайте и установите свой проект Android как обычно. Если ваш собственный код находится в каталоге jni/ , сценарий сборки автоматически упаковывает файлы .so , созданные на его основе, в APK.

Дополнительный пример кода

Чтобы скачать образцы NDK, см. раздел «Образцы NDK» .