Встраиваем геолокацию от Huawei в Android приложение

от автора

image

В предыдущих статьях мы создавали аккаунт разработчика для использования Huawei Mobile Services и подготавливали проект к их использованию. И использовали аналитику от Huawei вместо аналога от Google. В этой статье мы будем встраивать определение геолокации от Huawei.

Вот полный список статей из цикла:

  1. Создаём аккаунт разработчика, подключаем зависимости, подготавливаем код к внедрению. тык
  2. Встраиваем Huawei Analytics. тык
  3. Используем геолокацию от Huawei. ← вы тут
  4. Huawei maps. Используем вместо Google maps для AppGallery.

Как должен выглядеть код в уже готовом проекте

Исходить будем, опять таки, из того, что у вас геолокация для гугла сделана примерно так:

1) Для проверки разрешения пользователя на доступ к его местоположению использована библиотека RxPermissions примерно так:

class PermissionsHelper {      private var rxPermissions: RxPermissions? = null      /**      * Вызываем в Activity#onCreate      */     fun attach(activity: FragmentActivity) {         rxPermissions = RxPermissions(activity)     }      /**      * Вызываем в Activity#onDestroy      */     fun detach() {         rxPermissions = null     }      fun requestPermission(vararg permissionName: String): Single<Boolean> {         return rxPermissions?.request(*permissionName)             ?.firstOrError()             ?: Single.error(                 IllegalStateException("PermissionHelper is not attached to Activity")             )     } }

2) Создан свой класс для местоположения:

data class Location(     val latitude: Double,     val longitude: Double ) {     companion object {         val DEFAULT_LOCATION = Location(59.927752, 30.346944)     } }

3) Создана абстракция над поставщиком местоположения:

interface FusedLocationClient {      fun checkPermissions(): Single<Boolean>      fun getLastLocation(): Single<Location>      fun requestLastLocation(): Single<Location> }

4) И используется она примерно так:

class LocationGateway(     private val fusedLocationClient: FusedLocationClient ) {      fun requestLastLocation(): Single<Location> {         return fusedLocationClient.checkPermissions()             .flatMap { granted ->                 if (granted) {                     fusedLocationClient.getLastLocation()                         .onErrorResumeNext(fusedLocationClient.requestLastLocation())                 } else {                     Single.just(Location.DEFAULT_LOCATION) // или ошибку кидаем какую-то                 }             }     } }

Используем разные реализации определения геолокации

Если вышеописанное верно для вашего случая, то как и в случае с аналитикой нам понадобятся 2 разные реализации FusedLocationClientFusedLocationClientImpl:

1) В папке src/huawei/kotlin/com/example:

class FusedLocationClientImpl(     private val permissionsHelper: PermissionsHelper,     context: Context ) : FusedLocationClient {      private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)      override fun checkPermissions(): Single<Boolean> {         val permissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION)         // Add this permission too after API=28 if you want to receive location in background         // if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {         //     permissions += Manifest.permission.ACCESS_BACKGROUND_LOCATION         // }         return permissionsHelper.requestPermission(*permissions.toTypedArray())     }      override fun getLastLocation(): Single<Location> {         return Single.create { singleEmitter ->             fusedLocationClient.lastLocation                 .addOnFailureListener {                     if (singleEmitter.isDisposed) return@addOnFailureListener                      singleEmitter.onError(it)                 }                 .addOnSuccessListener { newLocation ->                     if (singleEmitter.isDisposed) return@addOnSuccessListener                      if (newLocation == null) {                         singleEmitter.onError(UnknownLocationException())                     } else {                         singleEmitter.onSuccess(                             Location(                                 newLocation.latitude,                                 newLocation.longitude                             )                         )                     }                 }         }     }      override fun requestLastLocation(): Single<Location> {         return Single.create { singleEmitter ->              val locationRequest = LocationRequest.create()                 .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)                 .setInterval(5000)                 .setSmallestDisplacement(5.5F)                 .setNumUpdates(1)              val callback = object : LocationCallback() {                 override fun onLocationResult(result: LocationResult) {                     if (singleEmitter.isDisposed) return                      singleEmitter.onSuccess(                         Location(                             result.lastLocation.latitude,                             result.lastLocation.longitude                         )                     )                 }             }              fusedLocationClient.requestLocationUpdates(locationRequest, callback, null)              singleEmitter.setCancellable {                 fusedLocationClient.removeLocationUpdates(callback)             }         }     } }

2) В папке src/google/kotlin/com/example:

class FusedLocationClientImpl(     private val permissionsHelper: PermissionsHelper,     context: Context ) : FusedLocationClient {      private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)      override fun checkPermissions(): Single<Boolean> {         val permissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION)         // Add this permission too after API=28 if you want to receive location in background         // if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {         //     permissions += Manifest.permission.ACCESS_BACKGROUND_LOCATION         // }         return permissionsHelper.requestPermission(*permissions.toTypedArray())     }      @SuppressLint("MissingPermission")     override fun getLastLocation(): Single<Location> {         return Single.create { singleEmitter ->             fusedLocationClient.lastLocation                 .addOnFailureListener {                     if (singleEmitter.isDisposed) return@addOnFailureListener                      singleEmitter.onError(it)                 }                 .addOnSuccessListener { newLocation ->                     if (singleEmitter.isDisposed) return@addOnSuccessListener                      if (newLocation == null) {                         singleEmitter.onError(UnknownLocationException())                     } else {                         singleEmitter.onSuccess(                             Location(                                 newLocation.latitude,                                 newLocation.longitude                             )                         )                     }                 }         }     }      @SuppressLint("MissingPermission")     override fun requestLastLocation(): Single<Location> {         return Single.create { singleEmitter ->              val locationRequest = LocationRequest.create()                 .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)                 .setInterval(5000)                 .setSmallestDisplacement(5.5F)                 .setNumUpdates(1)              val callback = object : LocationCallback() {                 override fun onLocationResult(result: LocationResult) {                     if (singleEmitter.isDisposed) return                      singleEmitter.onSuccess(                         Location(                             result.lastLocation.latitude,                             result.lastLocation.longitude                         )                     )                 }             }              fusedLocationClient.requestLocationUpdates(locationRequest, callback, null)              singleEmitter.setCancellable {                 fusedLocationClient.removeLocationUpdates(callback)             }         }     } }

В итоге реализации отличаются только импортами)

Аналогично с аналитикой, в DI биндим для типа FusedLocationClient экземпляр FusedLocationClientImpl. Для разных сборок будет взята та или иная реализация.
Ну и не забываем, конечно, зависимости в скрипте сборки прописать:

dependencies {   huaweiImplementation 'com.huawei.agconnect:agconnect-core:1.3.1.300'   huaweiImplementation 'com.huawei.hms:location:5.0.0.301'    googleImplementation 'com.google.android.gms:play-services-location:17.0.0' }

И не забудьте добавить разрешение на доступ к местоположению в фоне если в приложении планируется такой вариант использования сервиса! Если такое разрешение уже есть в файле AndroidManifest.xml — то можете этот пункт пропустить. Если нет — добавьте его:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="com.example">      <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </manifest>

Подводные камни

Надо иметь в виду, что геолокация от Huawei будет работать при следующих условиях:

  1. У вас установлены Huawei Mobile Services на девайсе.
  2. Им выданы нужные разрешения.

Дальше — встраиваем карты

С геолокацией мы разобрались, в следующей статье покажем как встроить карты от Huawei в приложение, которое уже использует аналог от Google.

Весь код, который есть в этом цикле статей вы можете посмотреть в репозитории на GitHub. Вот ссылка: https://github.com/MobileUpLLC/huawei_and_google_services.

ссылка на оригинал статьи https://habr.com/ru/post/521806/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *