Huawei Services, зачем, почему и как собирать проект?

Немного вводных
Huawei поставляет Android-смартфоны без сервисов Google и привычного магазина приложений Google Play, создав аналоги: Huawei Services и AppGallery.
Для нас, разработчиков, это 420 миллионов активных пользователей на 700 миллионов устройств. Для поддержки пользователей потребуется оформление документов. В статье мы поговорим только о использование сервисов.
Настройка проекта
Уверен, что вы сможете адаптировать инструкцию под вашу версию Gradle,
архитектуру проекта, Kotlin DSL.
Для настройки проекта требуется конфигурационный файл agconnect-services.json аналог google-services.json. Получаем его в консоли разработчика после регистрации проекта.
build.gradle (project)
buildscript { repositories { google() maven { url 'https://developer.huawei.com/repo/' } } dependencies { .... classpath 'com.huawei.agconnect:agcp:1.4.2.301' } } allprojects { repositories { google() maven { url 'https://developer.huawei.com/repo/' } } }
build.gradle (app)
if(getGradle().getStartParameter().getTaskNames().toString().toLowerCase().contains("huawei")) { apply plugin: 'com.huawei.agconnect' } else { //Плагины других сервисов } dependencies { ... implementation "com.huawei.agconnect:agconnect-core:1.4.1.300” ... }
Для ProGuard:
-ignorewarnings -keep class com.huawei.agconnect.**{*;}
Для DexGuard:
-ignorewarnings -keep class com.huawei.agconnect.** {*;} -keep resourcexmlelements ** -keep resources */*
Если есть потребность поддерживать несколько площадок(AppGallery, Google Play)
и сервисов(Huawei, Google), то надо учитывать достаточно частую смену политик маркетов.
Google в одном из обновлений запретила размещать приложения c зависимостями от Huawei Services. Лучшим решением будет разделение сборок.
Отдельные сборки Huawei и Google
Есть несколько реализаций и самый простой выглядит так.
Подготовить build flavours
huaweiиgoogleflavorDimensions "mobileServices" productFlavors { google { dimension "mobileServices" } huawei { dimension "mobileServices" applicationIdSuffix ".huawei" } }Разделить все зависимости в build.gradle (app) с помощью
googleImplementation
иhuaweiImplementationdependencies { ... huaweiImplementation "com.huawei.agconnect:agconnect-core:1.4.1.300” ... }Положить
agconnect-services.jsonв директорию src/huawei ,
аgoogle-services.jsonв директорию src/google. Так как они нужны только для определённой сборки и application package у них разные. Для публикации huawei сборки к пакету обязательно добавляется “.huawei”В директории
src/mainсоздаём интерфейс будущего сервиса, а реализацию кладём в директорииsrc/huaweiиsrc/google. Названия будут те, которые указаны вproductFlavors. При выборе варианта сборки запустится синхронизация Gradle файлов и подставится нужная реализация.

Рассмотрим пример с MessagingService
Важно учитывать ваш подход к асинхронной/мультипоточной работе. В Google Services есть класс Task для получения callback'ов, но в Huawei Services его нет. Kotlin coroutine подходят на замену своей легковесностью. Тогда бы мы использовали suspend function.
Допустим у нас жёсткими ограничениями на библиотеки и нет корутин. Тогда можно вспомнить старый добрый Thread. Прекрасное решение, но дорогое, поэтому у нас будет ThreadPoolExecutor, настроенный под наши нужды.
class MessagingServiceImpl : MessagingService { private var executor: ввExecutorService = ThreadPoolExecutor( CORE_THREAD_POOL_SIZE, MAX_THREAD, KEEP_ALIVE_THREAD_TIME, TimeUnit.SECONDS, LinkedBlockingQueue(CAPACITY_QUEUE), ThreadUtils().threadFactory(Process.THREAD_PRIORITY_BACKGROUND) ) private val handler = HandlerCompat.createAsync(Looper.getMainLooper()) override fun getToken(successCallback: (token: String) -> Unit) { val task = Callable { val token = instanceId.getToken(appId, tokenScope) if (token != null && token.isNotEmpty()) handler.post { successCallback(token) } } executor.submit(task) } override fun deleteToken(successCallback: () -> Unit) { val task = Callable { instanceId.deleteToken(appId, tokenScope) handler.post { successCallback() } } executor.submit(task) } companion object { private const val CORE_THREAD_POOL_SIZE = 0 private const val MAX_THREAD = 1 private const val KEEP_ALIVE_THREAD_TIME = 5L private const val CAPACITY_QUEUE = 1 } } class ThreadUtils { fun threadFactory( priority: Int ): ThreadFactory = PriorityThreadFactory(priority) } private class PriorityThreadFactory( private val threadPriority: Int ) : ThreadFactory { override fun newThread(runnable: Runnable): Thread { val wrapperRunnable = Runnable { try { Process.setThreadPriority(threadPriority) } catch (throwable: Throwable) { Timber.e(throwable) } runnable.run() } return Thread(wrapperRunnable) } }
Вуаля, мы рассмотрели замену Task'ам и подготовили проект для подключения нужных нам сервисов, которое используют идентичное Google Services api.

Tooling
Если у вас есть большой проект с сервисами Google, то плагин ide HMS Toolkit будет очень полезный.
Основные функции:
Анализ всех мест использования Google сервисов
Замена Google сервисов на Huawei
Предупреждение 1
Плагин зависит от версии Androi Studio. На последних версиях плагин в сторе плагинов внутри студии не найдёшь. Для работы отдельно можно скачать студию более низкой версии.
Предупреждение 2
Если вам пришлось скачать Android Studio более низкой версии
(Смотри предупреждение 1), после установки и открытия проекта можно получить ошибку несовместимости Gradle.
После анализа есть два варианта действий:
Add HMS API. На основе существующих в проекте GMS APIs генерируется XMS adapter (как дополнительный модуль в проекте). Он представляет собой прослойку между нашим кодом и непосредственно вызовом сервисов. Это такие Extension-классы, в которых лежит код, поддерживающий HMS и GMS сервисы одновременно. Add HMS API(в скобках описывается приоритет). В runtime определяется поддерживаемый девайсом вид сервисов и вызываются соответствующие методы. Наш вариант
To HMS API – полностью заменяются GMS APIs на HMS APIs.
При желании результаты анализа можно экспортировать, например, в pdf.
Debugging
Всё готово и мы ничего не пропустили. Теперь нам нужно протестировать работоспособность сервисов, но у нас может не быть нужного устройства. Тогда на помощь приходит облачная платформа DigiX Lab для дебага и тестов.
Как можно догадаться, Cloud Debugging предоставляет бесплатное решение для облачной отладки, позволяющее решать такие проблемы:
Недостаточное количество моделей устройств
Сложности в управлении устройствами
Невозможность воспроизвести ошибки
Затраты на покупку и управление устройствами
Цель Cloud Testing — это тестирование совместимости, стабильности, производительности и энергопотребления ваших приложений на мобильных устройствах Huawei, а также создание отчётов.
Непрерывная доставка
Для автоматизации сборки можно воспользоваться Publishing API
