Одной из основных проблем, с которыми мы столкнулись при разработке NDK для нашего Android Video SDK, стала интеграция с предписанным Android Studio рабочим процессом на основе Gradle. Наша главная трудность заключалась в отладке нативных компонентов внутри Android-библиотеки. Последние обновления Android Studio и Android Gradle Plugin показывают, что Google инвестирует в улучшение опыта разработчиков для нативной разработки на Android и обеспечивает её полноценную поддержку в своей флагманской IDE. Мы внимательно следили за прогрессом этого нового плагина. Недавнее добавление поддержки статических библиотек побудило нас глубоко изучить миграцию с традиционного рабочего процесса на основе Application.mk, Android.mk и ndk-build. Мы решились на этот шаг и хотим поделиться некоторыми нашими находками в процессе перехода на новый рабочий процесс сборки.
Новый экспериментальный плагин должен быть знаком пользователям Gradle и тем, кто знаком с процессом сборки NDK. Большинство привычных флагов доступны в модели `android.ndk`. Полная документация Google по экспериментальному плагину доступна здесь.
Мы подготовили пример процесса миграции, который отражает некоторые из проблем, с которыми мы столкнулись и которые не упоминаются в текущей документации. В разделах ниже приведены примеры микроконверсий, чтобы вы могли воссоздать свои .mk-файлы в build.gradle.
Примеры NDK дают хорошее представление о экспериментальном плагине и о том, как его можно использовать в нативной разработке. Новый плагин использует новый модельный подход Gradle. Следующий фрагмент кода показывает базовую конфигурацию модели, которая будет дополнена в последующих преобразованиях.
Как уже упоминалось, мы разработали этот пример процесса миграции, чтобы выделить следующие проблемы, с которыми мы столкнулись:
1. Использование отладочных сборок наших нативных зависимостей
2. Включение статических библиотек
3. Обработка зависимостей зависимостей (foo.a зависит от bar.a)
4. Объявление целой статической библиотеки (—whole-archive)
Вот файл Android.mk, который демонстрирует каждую из этих проблем:
Для подключения статических библиотек требуется добавление записей libs в нашу модель репозиториев. Следующий фрагмент кода демонстрирует решения для первой и второй проблем. Обратите внимание на отсутствие my-whole-static-library.
До этого момента процесс миграции можно было бы выполнить, просто следуя примерам NDK и изучая руководство по экспериментальному плагину. Давайте вернёмся к оставшимся проблемам:
— Обработка зависимостей зависимостей (foo.a зависит от bar.a)
— Объявление целой статической библиотеки (—whole-archive)
Решения для этих проблем несколько сложнее, и вот почему:
**Первое предположение**
Предположим, что нам не нужна `whole-static-library`, и мы можем просто продолжить с нашими двумя другими статическими библиотеками, но, как уже упоминалось, `my-other-static-library` зависит от `my-static-library`. Это означает, что если бы мы попытались скомпилировать, Gradle пожаловался бы на невозможность разрешения символов на этапе компоновки. Мы могли бы добавить `whole-static-library` в наш массив `ldLibs`, но нет механизма для указания конкретной архитектуры.
**Второе предположение**
Предположим, что третьей проблемы не существует, и мы добавляем `whole-static-library` так же, как и другие. Мы смогли бы скомпилировать, но столкнулись бы с исключениями «метод не найден», если бы вызывали нативные методы из Java-слоя, потому что компилятор удалит функции, которые он считает неиспользуемыми. Мы могли бы вручную добавить whole-static-library в ldFlags, обернув его в `—whole-archive`, но опять же, у нас нет возможности указать архитектуру.
Решения для третьей и четвёртой проблем потребовали некоторых исследований конфигурации модели на основе правил, находящейся на стадии инкубации в Gradle, и понимания задач, генерируемых экспериментальным плагином. Если выполнить команду ./gradlew tasks —all в нашем примере, можно обнаружить следующее:
Эти задачи посвящены компоновке, и если мы изменим аргументы, передаваемые компоновщику, то сможем решить третью и четвёртую проблемы: обработку зависимостей зависимостей и объявление целой статической библиотеки. Создав RuleSource, мы можем применять мутации к моделям в конфигурации Gradle. Вот фрагмент кода, показывающий, как изменить каждую из этих задач компоновки. Этот фрагмент можно добавить в конец файла build.gradle:
Существует несколько публикаций о создании Javadoc для проектов Android-библиотек, но они не применимы к этому новому экспериментальному плагину. Вот простой фрагмент для добавления задачи создания Javadoc в ваш проект:
Хотя процесс оказался несколько сложнее, чем мы ожидали, миграция на экспериментальный плагин оказалась гораздо более подходящей для нативной разработки на Android. Дополнительные преимущества, такие как автодополнение кода, гибридный режим отладки и гибкость Gradle, принесли значительные улучшения в эффективности разработки нашего Android SDK. Несмотря на то что плагин помечен как экспериментальный, его стабильность впечатляет, а интеграция с Android Studio 2.0 проходит безупречно. К сожалению, документация по плагину немного скудна, и начальный этап может быть пугающим, но в целом преимущества стоят затраченных усилий.
*Подписывайтесь на Аарона Аланиза в Twitter здесь @webheadz3.*