Play Services для Kotlin: полное руководство с примерами
Google Play Services — это мощный набор сервисов и API от Google, предоставляющий разработчикам Android доступ к ключевым функциям платформы. Сюда входят: геолокация, карты (Maps), авторизация (Auth), push-уведомления (Firebase Cloud Messaging), аналитика, платежи, работа с камерой и AR, синхронизация игр (Play Games) и многое другое. Библиотека Play Services является обязательной для большинства современных Android-приложений, так как она берёт на себя рутинные задачи по взаимодействию с системными службами и обеспечивает единый, стабильный интерфейс, независимо от версии Android на устройстве.
Зачем нужна эта библиотека? Во-первых, она абстрагирует сложность работы с системными API. Вместо того чтобы писать код для каждого производителя устройств (Samsung, Xiaomi, Huawei), вы используете единый API от Google, который гарантирует совместимость. Во-вторых, Play Services обновляются автоматически через Google Play Store, что позволяет вам использовать новейшие функции без необходимости обновлять само приложение. В-третьих, библиотека оптимизирует энергопотребление и производительность: например, для геолокации используется аппаратное ускорение и пакетная обработка запросов.
Для языка Kotlin, который является официальным языком разработки Android, Play Services предоставляет полностью совместимые Kotlin-расширения (KTX). Это значит, что вы можете писать более лаконичный и безопасный код, используя корутины, лямбды и extension-функции. В этой статье мы рассмотрим основные модули Play Services, их установку, ключевые методы и напишем полноценное приложение, демонстрирующее работу с геолокацией, картами и авторизацией.
Установка
Play Services — это не отдельная библиотека, а набор модулей. Вы подключаете только те, которые нужны вашему приложению. Установка производится через систему сборки Gradle (аналог pip для Python, но для Android).
1. Откройте файл build.gradle.kts (уровень проекта) и убедитесь, что добавлен репозиторий Google:
// build.gradle.kts (Project)
allprojects {
repositories {
google()
mavenCentral()
}
}
2. В файле build.gradle.kts (уровень модуля — app) добавьте зависимости. Пример для модулей: Maps, Location, Auth и Base (обязательный):
// build.gradle.kts (Module: app)
dependencies {
// Базовая библиотека Play Services (обязательна)
implementation("com.google.android.gms:play-services-base:18.5.0")
// Google Maps
implementation("com.google.android.gms:play-services-maps:19.0.0")
// Геолокация
implementation("com.google.android.gms:play-services-location:21.3.0")
// Авторизация (Google Sign-In)
implementation("com.google.android.gms:play-services-auth:21.2.0")
// Kotlin-расширения (KTX) для корутин
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
}
3. Синхронизируйте проект (Sync Now). После этого все API станут доступны в коде.
Важно: Версии библиотек постоянно обновляются. Рекомендуется проверять актуальные версии на официальной странице релизов.
Быстрый старт: минимальный пример
Создадим простое приложение, которое получает текущие координаты устройства и выводит их на экран. Для этого нам понадобится модуль play-services-location.
1. Добавьте разрешения в AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
2. Код Activity (Kotlin):
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
class MainActivity : AppCompatActivity() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationText: TextView
// Регистрируем обработчик запроса разрешений
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val fineGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false
val coarseGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false
if (fineGranted || coarseGranted) {
getLastLocation()
} else {
Toast.makeText(this, "Разрешение не получено", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
locationText = findViewById(R.id.location_text)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
// Проверяем и запрашиваем разрешения
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED -> {
getLastLocation()
}
else -> {
requestPermissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
}
}
@SuppressLint("MissingPermission")
private fun getLastLocation() {
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
if (location != null) {
locationText.text = "Широта: ${location.latitude}\nДолгота: ${location.longitude}"
} else {
locationText.text = "Местоположение недоступно"
}
}.addOnFailureListener { e ->
locationText.text = "Ошибка: ${e.message}"
}
}
}
Этот минимальный пример показывает, как запросить разрешение, получить клиент геолокации и выполнить асинхронный запрос на получение последнего известного местоположения.
Основные методы, функции и классы
Рассмотрим 8 ключевых классов/методов из разных модулей Play Services. Для каждого приведена сигнатура (упрощённая), описание и пример.
1. FusedLocationProviderClient.lastLocation
Сигнатура: suspend fun lastLocation: Task<Location?> (через Task API) или suspend fun awaitLastLocation(): Location? (через KTX)
Описание: Возвращает последнее известное местоположение устройства. Это самый быстрый способ получить координаты, но точность может быть низкой, если данные устарели.
// Использование с корутинами (play-services-location-ktx)
lifecycleScope.launch {
val location = fusedLocationClient.awaitLastLocation()
if (location != null) {
println("Lat: ${location.latitude}, Lng: ${location.longitude}")
}
}
2. FusedLocationProviderClient.requestLocationUpdates
Сигнатура: fun requestLocationUpdates(request: LocationRequest, callback: LocationCallback, looper: Looper?): Task<Void>
Описание: Запускает периодическое получение обновлений геолокации с заданными параметрами (интервал, приоритет). Используется для навигации или трекинга.
val locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY, 5000 // 5 секунд
).apply {
setMinUpdateIntervalMillis(2000)
setMaxUpdateDelayMillis(10000)
}.build()
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
for (location in result.locations) {
println("Новое местоположение: ${location.latitude}, ${location.longitude}")
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, mainLooper)
3. GoogleSignInClient.silentSignIn
Сигнатура: fun silentSignIn(): Task<GoogleSignInAccount>
Описание: Пытается выполнить "тихий" вход в аккаунт Google без показа UI. Если пользователь уже авторизован, возвращает аккаунт. Иначе — исключение.
val signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_SIGN_IN)
lifecycleScope.launch {
try {
val account = signInClient.silentSignIn().await()
println("Успешный вход: ${account.email}")
} catch (e: ApiException) {
println("Тихий вход не удался: ${e.statusCode}")
// Показать UI входа
}
}
4. GoogleSignInClient.signOut
Сигнатура: fun signOut(): Task<Void>
Описание: Выполняет выход из аккаунта Google. После вызова silentSignIn вернёт ошибку.
signInClient.signOut().addOnCompleteListener {
println("Выход выполнен")
}
5. GoogleMap.addMarker
Сигнатура: fun addMarker(options: MarkerOptions): Marker
Описание: Добавляет маркер на карту Google Maps. Параметры: позиция, заголовок, иконка и т.д.
// Предполагаем, что mapFragment уже загружен
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync { googleMap ->
val sydney = LatLng(-33.852, 151.211)
googleMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Сидней")
.snippet("Самый большой город Австралии")
)
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15f))
}
6. GoogleMap.setOnMarkerClickListener
Сигнатура: fun setOnMarkerClickListener(listener: GoogleMap.OnMarkerClickListener?)
Описание: Устанавливает слушатель кликов по маркерам. Возвращает true, если событие обработано.
googleMap.setOnMarkerClickListener { marker ->
Toast.makeText(this, "Нажат маркер: ${marker.title}", Toast.LENGTH_SHORT).show()
true // Событие обработано, стандартное поведение (инфо-окно) не показывается
}
7. PlacesClient.findCurrentPlace
Сигнатура: fun findCurrentPlace(request: FindCurrentPlaceRequest): Task<FindCurrentPlaceResponse>
Описание: Определяет текущее место (Place), где находится устройство, на основе данных геолокации и базы Google. Возвращает список вероятных мест.
val placesClient = Places.createClient(this)
val request = FindCurrentPlaceRequest.builder(
listOf(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
).build()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
placesClient.findCurrentPlace(request).addOnSuccessListener { response ->
for (placeLikelihood in response.placeLikelihoods) {
println("Место: ${placeLikelihood.place.name}, Вероятность: ${placeLikelihood.likelihood}")
}
}
}
8. Task.await() (из KTX)
Сигнатура: suspend fun <T> Task<T>.await(): T
Описание: Kotlin-расширение, которое преобразует асинхронный Task в корутину. Позволяет писать последовательный код без колбэков.
// Без await (колбэки)
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
// обработка
}
// С await (корутины)
lifecycleScope.launch {
val location = fusedLocationClient.lastLocation.await()
// обработка
}
Реальный практический пример (150+ строк)
Создадим приложение "Мой трекер", которое отображает текущее местоположение на карте, позволяет ставить метки и показывает список последних координат. Используем модули: Maps, Location, а также корутины.
Шаг 1. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="ВАШ_API_КЛЮЧ_ДЛЯ_MAPS" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Шаг 2. activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match