Как стать автором
Обновить
inDrive.Tech
Global Unicorn with Developers Driving the Growth

Как мы в андроид приложение inDriver добавили поддержку Harmony OS

Время на прочтение 5 мин
Количество просмотров 6K
Все началось с того, что министерство торговли США включило Huawei в список компаний, с которыми запрещено вести бизнес американским компаниям. Ответом Huawei стала операционная система Harmony OS для своих смартфонов, и отказ использовать в ней сервисы Google. И чтобы не потерять часть рынка, мы интегрировали в inDriver ее поддержку. Хотя «интеграция OS» звучит громко – наше приложение, как и любое другое, написанное под Android, запустится на Harmony, но для полноценной работы необходимо заменить Google-сервисы на аналогичные Huawei.



В inDriver мы используем сервисы Google для 3 целей:

  • Отправление пуш уведомлений;
  • Определение локации;
  • Google карты.

Push Kit – отправление push-уведомлений


Для начала, у Huawei есть неплохая документация. Но для быстрого старта достаточно использовать step-by-step туториал.

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

Enabling the Service

Вас попросят установить Data Storage Location. Учтите, что его потом нельзя изменить. Локация не влияет на непосредственную работу пушей, а является лишь местом хранения и обработки данных о них.

Integrating the HMS SDK

После того как вы закончите интеграцию, у вас вероятно будут проблемы со сборкой проекта. Во всяком случае, так было у нас на билд сервере Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-174-generic x86_64), при этом локально на рабочем Mac mini (late 2018, Mojave) все работало нормально.

Execution failed for task ':app:processIndriverReleaseManifest'. org.gradle.api.GradleException: ERROR: no manifest file found

Исправить это можно, если добавить

agcp {
   manifest false
}

в конец файла build.gradle на уровне приложения, чтобы отключить манифест для agcp. Тут скорее проблема в том, что agcp ищет файл-манифест, но не может его найти и загрузить, что вероятнее всего является проблемой agconnect. По крайней мере, именно так нам ответила официальная техническая поддержка Huawei.

Configuring AndroidManifest.xml

Не знаю почему, но тут не сказано про автоматическую инициализацию, про которую написано в пункте 2.6 Automatic Initialization полной документации. Это необходимо, если вы отправляете токен на сервер в методе

public void onNewToken(String token) {}

Sending Messages: HUAWEI Push Kit Console.

С его помощью вы можете проверить работу пушей. Интересный факт: если вы в консоли выберете Type: Notification Message, то они в обход обработчика onMessageReceived(RemoteMessage message) сразу будут отображены на телефоне.

Когда я настраивал работу пушей, мне часто приходилось пользоваться консолью. И у нее, и у пушей отправленных с сервера, были задержки вплоть до 30 минут. Надеюсь, это были временные трудности, с которыми разработчики уже справились.

Теперь у нас на телефоне есть два пуш-сервиса, но как их организовать их совместную работу? Для начала надо определить, какие сервисы доступны на телефоне. Мы у себя решили, что Google-сервисы будут для нас в приоритете. Допустим, если на телефоне доступны и Google-, и Huawei-сервисы, мы работаем с Google.

На сервер мы отправляем флаг состояния сервисов с возможными значениями:

- UNKNOWN
- GOOGLE
- HUAWEI

fun checkServices(context: Context): PlayServicesState {
   val googleAPI = GoogleApiAvailability.getInstance()
   when (googleAPI.isGooglePlayServicesAvailable(context)) {
       ConnectionResult.SUCCESS,
       ConnectionResult.SERVICE_MISSING,
       ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED,
       ConnectionResult.SERVICE_DISABLED -> return PlayServicesState.GOOGLE
   }
   val huaweiAPI = HuaweiApiAvailability.getInstance()
   when (huaweiAPI.isHuaweiMobileNoticeAvailable(context)) {
       com.huawei.hms.api.ConnectionResult.SUCCESS,
       com.huawei.hms.api.ConnectionResult.SERVICE_MISSING,
       com.huawei.hms.api.ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED,
       com.huawei.hms.api.ConnectionResult.SERVICE_DISABLED -> return PlayServicesState.HUAWEI
   }
   return PlayServicesState.UNKNOWN
}

В зависимости от полученного значения, сервер будет отправлять пуш-нотификации в соответствующий сервис.

Организовать их работу является делом техники. Я поступил просто.

Обработка событий для FCM:

class AppFcmListenerService : FirebaseMessagingService() {
   private val cloudMessageHandler: CloudMessageHandler = GoogleMessageHandler(this)
   override fun onMessageReceived(message: RemoteMessage) {
       cloudMessageHandler.onMessageReceived(message)
   }
}

и HCM:

class AppHmsListenerService : HmsMessageService() {
   private val cloudMessageHandler: CloudMessageHandler = HuaweiMessageHandler(this)
   override fun onMessageReceived(message: RemoteMessage) {
       cloudMessageHandler.onMessageReceived(message)
   }
}

делегируется абстрактному классу:

abstract class CloudMessageHandler { 
fun onMessageReceived(message: Any) {
   val data = getData(message)
   onMessageReceived(data)
}
private fun onMessageReceived(data: Map<String, String>) {
   //непосредственная обработка пушей 
}
abstract fun getData(message: Any) :  Map<String, String> {
}

который имеет две имплементации:

для FCM:

class FirebaseMessageHandler(override val context: Context) : CloudMessageHandler(context) {
   override fun getData(message: Any): Map<String, String> {
       return (message as RemoteMessage).data
   }
}

для HCM:

class HuaweiMessageHandler(override val context: Context) : CloudMessageHandler(context) {
   override fun getData(message: Any): Map<String, String> {
       return (message as RemoteMessage).dataOfMap
   }
}

Классы Huawei имеют почти схожий интерфейс с Google-сервисами. Это «почти» лично у меня проявилось в том, что у RemoteMessage из com.google.firebase.messaging для получения Map<String, String> нужно вызвать RemoteMessage.getData(), а для RemoteMessage из com.huawei.hms.pushgetDataOfMap().

Location Kit – определение локации


Определением локации может заниматься LOCATION_SERVICE, который доступен без Google и Huawei сервисов. Но для сервиса пассажирских перевозок точное определение локации является важным параметром. Благо, интерфейсы классов Location Kit ничем не отличались от одноименных для Google-сервисов, значит не отличалось и их применение в коде. Однако, сервисы Huawei оказались менее точными в работе. Надеюсь, это временная проблема.
Также мы столкнулись с тем, что запрос геолокации идет через HMS Core, а значит для корректной работы необходимо выставить права для геолокации как «Разрешить всегда».

location

Замена Google карт


В СНГ мы использовали OSM движок с тайлами 2ГИС. На первом этапе интеграции мы решили не работать с Map Kit из HUAWEI, а просто использовать движок OSM с тайлами OSM. Все просто.

Перед релизом


Советую всем обратить внимание на распространенные причины отказа перед запуском вашего приложения в AppGallery.

Например, релизная команда Huawei сообщила нам о следующих нарушениях.

Non-Standard Presentation of Hong Kong and Macau

Китай щепетильно относится к суверенитету своих автономных административных районов и просит их назвать «region». Это вынудило нас изменить все заголовки, где упоминается страна на упоминание страны или региона.



Information about Third-party Competing Products in App Details

Не забудьте для оценки приложения отправить пользователя на страницу в App Gallery, а не Google Play Store :)

В целом Huawei-сервисы аналогичны Google-сервисам и поддержка их непосредственно в коде не вызывает трудностей. Вопросы могут быть только к Huawei «экосистеме» в целом, но их можно списать на ее молодость и с большой вероятностью все будет лучше со временем.
Теги:
Хабы:
+8
Комментарии 8
Комментарии Комментарии 8

Публикации

Информация

Сайт
indrive.com
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
США
Представитель
g_volgin

Истории