Иметь в проекте как GMS, так и HMS
Как сделать так, чтобы в приложении были и Google Mobile Services, и Huawei Mobile Services?
Поскольку Huawei потеряла лицензию на GMS, кажется, что нам нужно заменить все службы GMS, используемые в приложениях, на предоставленные Huawei. Что было бы для этого "лучшей практикой"? Использовать разновидности и как-то обрабатывать каждый класс индивидуально или копировать и вставлять проект и начинать замену? Или... еще лучше, есть ли способ, возможно, иметь и то, и другое и... каким-то образом позволить приложению решать, какую службу использовать, в зависимости от устройства, на котором оно находится? Очевидно, что последний предполагает увеличение размера файла apk.
Есть идеи?
6 ответов
Итак, мне удалось это сделать так:
Определены два вкуса
gms {
dimension "services"
buildConfigField "String", "SERVICE_USED", '"g"'
}
hms {
dimension "services"
buildConfigField "String", "SERVICE_USED", '"h"'
}
Я использую "g" и "h" в коде всякий раз, когда мне нужно решить, что делать, например: API требует deviceType
"android" или "iOS", а с включением сборки Huawei мы определили еще одну константу "huawei". я используюSERVICE_USED
чтобы знать, какую константу отправлять.
Затем я сделал это в верхней части build.gradle:
apply plugin: 'com.android.application'
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")) {
//*meh*
} else {
apply plugin: 'io.fabric'
}
потому что я использовал ткань (и ткань / firebase ... на самом деле не работает с HMS), и я также сделал это в самом низу build.gradle
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")) {
apply plugin: 'com.huawei.agconnect'
} else {
apply plugin: 'com.google.gms.google-services'
}
чтобы включить только нужный плагин.
I then started handling each thing that was using gms
(maps, location, push notifications, analytics) by making a wrapper and separating the code in each flavour. i.e. for push notifications i created a HPushNotif
which has an getToken
method. I define the same class and method in both flavours but I implement them according to the type of service (gms or hms).
I used this type of notation when including dependencies in the project:
//GMS stuff
gmsImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
gmsImplementation 'com.google.firebase:firebase-core:16.0.9'
gmsImplementation 'com.google.firebase:firebase-messaging:18.0.0'
gmsImplementation 'com.google.firebase:firebase-crash:16.2.1'
gmsImplementation 'com.google.android.gms:play-services-maps:16.1.0'
gmsImplementation 'com.google.android.gms:play-services-location:16.0.0'
gmsImplementation 'com.google.android.gms:play-services-tagmanager:16.0.8'
//HMS stuff
hmsImplementation 'com.huawei.agconnect:agconnect-core:1.0.0.300'
hmsImplementation 'com.huawei.hms:push:4.0.3.301'
hmsImplementation 'com.huawei.hms:maps:4.0.1.301'
hmsImplementation 'com.huawei.hms:location:4.0.3.303'
The gms
and hms
before the Implementation
refer to the name of the flavours. Those dependencies will only be loaded when the appropriate BuildVariant is selected (i.e. appropriate flavour is being built).
Basically I wrapped the logic for maps, analytics, location and push notifications for both cases. This is how the structure looks. Nothing special.
Вот и все. Когда они создавали HMS, они в основном копировали GMS класс за классом и метод за методом. Вы увидите, что точные имена методов точно соответствуют вызывающим параметрам и даже возвращаемым значениям. Они на 99,99% одинаковы. Это облегчает жизнь. По сути, вам просто нужно скопировать код в два класса и импортировать нужные вещи (вверху класса). Вам редко нужно менять код, который вы уже написали для GMS.
Надеюсь, это кому-то поможет.
Прежде чем я отвечу на ваш вопрос, вот краткое объяснение, что такое HMS и GMS:
- HMS - это аббревиатура от Huawei Mobile Services.
- GMS - это аббревиатура от Google Mobile Services.
Вы можете опубликовать свое приложение (которое использует библиотеки Google) в магазине приложений Huawei (названном AppGallery), но это приложение будет видно и доступно для загрузки только для устройств Huawei, содержащих HMS+GMS (все устройства до 2020 года имели HMS и GMS).
Однако в более новых телефонах, то есть серии Mate 30, P40, будет установлена только HMS. Поэтому, если вы хотите сделать свое приложение видимым для всех устройств Huawei (HMS+GMS и HMS), вам нужно будет реализовать в своем приложении функцию для определения того, какая услуга включена на устройстве пользователя. Он решит, какую функцию вызывать (т.е. инициализировать экземпляр Huawei Maps или Google Maps).
Вот код для обнаружения HMS и GMS:
Для мобильных сервисов Huawei мы используем:
HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context);
https://developer.huawei.com/consumer/en/doc/development/HMS-References/huaweiapiavailability
Для мобильных сервисов Google мы используем:
GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability
Вот код, как правильно обрабатывать обнаружение HMS и GMS:
public static boolean isHmsAvailable(Context context) {
boolean isAvailable = false;
if (null != context) {
int result = HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context);
isAvailable = (com.huawei.hms.api.ConnectionResult.SUCCESS == result);
}
Log.i(TAG, "isHmsAvailable: " + isAvailable);
return isAvailable;
}
public static boolean isGmsAvailable(Context context) {
boolean isAvailable = false;
if (null != context) {
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
isAvailable = (com.google.android.gms.common.ConnectionResult.SUCCESS == result);
}
Log.i(TAG, "isGmsAvailable: " + isAvailable);
return isAvailable;
}
AFAIK эти классы (HuaweiApiAvailability/GoogleApiAvailability) доступны, если вы реализуете какой-либо из комплекта Huawei / библиотеки Google.
Хотя это действительно зависит от архитектуры вашего приложения, пока есть 2 разумные альтернативы;
- Использование вкусов и вариантов даст вам больше гибкости. Создание архитектуры и реализации займет относительно больше времени, но это чистый подход, обеспечивающий хорошую изоляцию кода. Поскольку эти экосистемы имеют разные рынки (AppGallery для Huawei), со своими вкусами и вариантами, очень удобно установить отдельные конвейеры сборки. Это дает вам возможность поддерживать разные apk для разных экосистем.
- Использование подхода обертка / мост. Просто реализуйте классы-оболочки для принятия решения и пересылки запросов на соответствующие конечные точки. При таком подходе можно поддерживать единый для обоих рынков. HMS на самом деле предоставляет для этого надежный инструмент. Он анализирует код, зависящий от GMS, затем автоматически генерирует классы-оболочки и преобразует исходный код для использования классов-оболочек. Он называется "HMS Converter" и даже имеет плагин для Android Studio. https://developer.huawei.com/consumer/en/huawei-toolkit/
Синтезирование всех хороших ответов, данных ранее: https://github.com/abusuioc/from-gms-to-hms#step-5-integrate-hms-sdks-in-your-app
Для большинства приложений рекомендуется использовать единую сборку с зависимостями как от GMS, так и от HMS SDK + решение во время выполнения (в зависимости от доступности на устройстве).
Я создал минимальный пример с
google
и
huawei
в виде . Дополнительные свойства проекта
usesGms
и
usesHms
оба по умолчанию
false
и один из них будет включен (что разрешает альтернативные зависимости), и он также применяет соответствующий плагин Gradle.
Корень :
project.ext.set('usesGms', false);
project.ext.set('usesHms', false);
buildscript {
repositories {
google()
mavenCentral()
maven { url "https://developer.huawei.com/repo/" }
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.0"
classpath "com.google.gms:google-services:4.3.10"
classpath "com.huawei.agconnect:agcp:1.6.0.300"
}
}
Уровень модуля
build.gradle
:
android {
...
flavorDimensions "vendor"
productFlavors {
google {
dimension "vendor"
versionNameSuffix "-google"
apply plugin: "com.google.gms.google-services"
project.ext.set('usesGms', true)
}
huawei {
dimension "vendor"
versionNameSuffix "-huawei"
apply plugin: "com.huawei.agconnect"
project.ext.set('usesHms', true)
}
}
// buildTypes should be defined after productFlavors,
// then project.ext.getProperty() can be already used
buildTypes { ... }
}
dependencies {
if (project.ext.getProperty('usesGms')) {
// Google & Firebase specific
implementation "com.google.android.gms:play-services-base:17.6.0"
implementation "com.google.firebase:firebase-core:19.0.0"
}
if (project.ext.getProperty('usesHms')) {
// Huawei & AppGallery Connect specific
implementation "com.huawei.hms:base:4.0.2.300"
implementation "com.huawei.agconnect:agconnect-core:1.5.2.300"
}
}
С
productFlavors
, зависимости также могут быть определены следующим образом:
googleImplementation "com.google.android.gms:play-services-base:17.6.0"
huaweiImplementation "com.huawei.hms:base:4.0.2.300"
И кажется, что можно настроить только одно имя пакета для каждого приложения (что в некоторых случаях делает его несовместимым с Firebase, если только не создаются два приложения) ... или, может быть, оно просто организовано по-другому? https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-config-flavor
Оба ответа @ AndreiBogdan и @ deadfish верны. Хочу еще немного добавить:
Во-первых, вам необходимо выбрать подходящее решение (G+H или G2H) на основе сценария приложения и затрат на разработку / тестирование.
- Если вы выбираете решение G+H, вам необходимо проверить, доступна ли GMS. Если интерфейс GMS не может использоваться должным образом, требуется HMS. Подробнее см. Ответ @deadfish. Вам рекомендуется использовать это решение, которое может
- Упростите упаковку приложений. Пакет может быть выпущен как в Google Play, так и в AppGallery.
- Уменьшите стоимость обслуживания кода. Код уровня адаптации HMS+GMS добавляется к исходному логическому коду. Таким образом, правильный код может быть автоматически вызван с мобильного телефона. То есть вам нужно только вызвать метод, чтобы проверить, доступна ли GMS для существующего логического кода, и вам не нужно поддерживать два набора кода.
Если вы выберете решение G2H, объем тестирования совместимости невелик. Вам нужно только протестировать новый APK на телефонах Huawei. Выпустите свое приложение как в HUAWEI AppGallery, так и в Google Play с разными пакетами. Приложение, которое вы публикуете в AppGallery, содержит только логический код Huawei. Вы можете обратиться к ответу @AndreiBogdan или просмотреть документы, поддерживающие несколько каналов.
Как говорит @ captaink, вы можете использовать HMS Toolkit Convertor. Он поддерживает преобразование G+H и G2H. В настоящее время HMS Toolkit поддерживает Java и Kotlin. Поддерживаемые версии Android Studio: 3.3.2~4.1.