Автомобильные интерфейсы становятся неотъемлемой частью повседневной жизни. Всё больше пользователей ожидают, что любимые приложения будут доступны не только на телефоне, но и на экране автомобиля. Для разработчика добавление поддержки Android Auto открывает не только новую аудиторию, но и возможность выделиться среди кандидатов на рынке труда. Проекты, связанные с автомобильными платформами, демонстрируют понимание современных трендов, умение работать со специфическими ограничениями и заботу о пользовательском опыте в условиях, где безопасность стоит на первом месте.
В этой статье мы покажем, как за один рабочий день добавить поддержку Android Auto в уже готовое приложение. Вы познакомитесь с Car App Library, научитесь создавать автомобильный сервис и адаптировать существующий код под экраны машин. Всё это мы протестируем на эмуляторе DHU, который уже обсуждали в предыдущей статье «Как запустить DHU для Android Auto». После прочтения вы сможете добавить полученный результат в портфолио и уверенно рассказать о нём на собеседовании.
Что потребуется:
Никаких специальных знаний об автомобильной разработке не нужно - мы разберём всё по шагам.
Чтобы приложение стало доступно в автомобиле, не нужно переписывать его целиком. Google предоставляет Car App Library - набор инструментов, который берёт на себя всю работу по взаимодействию с автомобильным хостом. Нам остаётся лишь создать автомобильный сервис, описать стартовый экран и добавить несколько зависимостей.
Откройте файл build.gradle вашего модуля (обычно app) и добавьте две библиотеки:
dependencies {
implementation 'androidx.car.app:app:1.2.0'
implementation 'androidx.car.app:app-projected:1.2.0'
}
Версия 1.2.0 - стабильная на момент написания статьи. Если вы используете более новую, проверьте актуальность в официальной документации. После синхронизации проект будет готов к автомобильным экспериментам.
В Android Auto взаимодействие с приложением происходит через специальный сервис, наследующий CarAppService. Он управляет жизненным циклом сессии и предоставляет объект Session, который, в свою очередь, создаёт экраны.
Создайте новый класс, например MyCarAppService, со следующим содержимым:
import android.content.Intent
import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.Screen
import androidx.car.app.CarContext
class MyCarAppService : CarAppService() {
override fun onCreateSession(): Session {
// Возвращаем объект Session, который будет управлять экранами
return object : Session() {
override fun onCreateScreen(intent: Intent): Screen {
// При запуске автомобильного приложения показываем наш главный экран
return MainScreen(carContext)
}
}
}
}
Пока MainScreen ещё не существует - мы создадим его чуть позже. Важно понимать: сервис создаётся один раз и живёт всё время, пока приложение активно в автомобиле.
Как любой сервис, его нужно объявить в AndroidManifest.xml. Кроме того, необходимо добавить разрешение на работу с поверхностью автомобиля (она нужна для отрисовки) и указать категорию приложения (например, навигация или простое приложение).
Добавьте следующие строки внутрь тега <manifest> (обратите внимание: разрешение должно быть на уровне манифеста, а не внутри <application>):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<application>
<service
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION" />
</intent-filter>
</service>
<!-- остальные компоненты приложения -->
</application>
</manifest>
Категория NAVIGATION подходит для приложений, которые помогают водителю ориентироваться. Если ваше приложение относится к другому типу (музыка, новости, подкасты), выберите соответствующую категорию. Полный список можно найти в документации.
Теперь автомобильная система сможет обнаружить наше приложение.
Самое время создать простой экран, который увидит водитель. В Car App Library все экраны строятся на основе шаблонов (Template). Самый универсальный - ListTemplate, который отображает список элементов.
Создайте класс MainScreen:
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.*
class MainScreen(carContext: CarContext) : Screen(carContext) {
override fun onGetTemplate(): Template {
// Строим одну строку с приветствием
val row = Row.Builder()
.setTitle("Добро пожаловать!")
.addText("Это автомобильная версия приложения")
.build()
// Добавляем её в список (используем addRow)
val list = ItemList.Builder()
.addRow(row)
.build()
// Оборачиваем список в шаблон
return ListTemplate.Builder()
.setTitle("Главное меню")
.setSingleList(list)
.build()
}
}
Этот экран покажет одну строку с текстом. Позже мы наполним его реальными данными из вашего приложения.
Теперь, когда основа готова, нужно связать автомобильный модуль с основной логикой приложения. Главная задача - не дублировать код, а использовать уже существующие репозитории, ViewModel и другие компоненты.
Самый чистый способ - вынести автомобильные экраны в отдельный модуль (например, :car), а общую бизнес-логику оставить в основном модуле или в модуле :core. Если ваш проект небольшой, можно оставить всё в одном модуле, но чётко разделить пакеты: ui.phone и ui.car. Так вы избежите случайного использования недоступных в автомобиле виджетов.
Для доступа к данным создайте интерфейс репозитория или use case, который будет общим для обеих версий. Например, для трекера поездок:
// Общий интерфейс в модуле :core
interface TripRepository {
fun getRecentTrips(limit: Int): List<Trip>
fun getTripById(id: String): Trip?
}
Реализация остаётся в основном модуле, а автомобильный модуль получает её через внедрение зависимостей (Hilt, Dagger или ручное DI).
Автомобильный интерфейс накладывает строгие ограничения: не более шести элементов в списке, минимум текста, обязательные иконки. Вам придётся переосмыслить, как показывать данные. Например, если в телефоне вы выводите подробную таблицу поездок, в машине уместны только последние три с крупными кнопками.
Вот как можно адаптировать экран списка поездок для автомобиля:
class TripsScreen(carContext: CarContext, private val repository: TripRepository) : Screen(carContext) {
override fun onGetTemplate(): Template {
val trips = repository.getRecentTrips(5) // берём не больше 5
val listBuilder = ItemList.Builder()
trips.forEach { trip ->
val row = Row.Builder()
.setTitle(trip.destination)
.addText(trip.distance)
.setOnClickListener { // открыть детали поездки
val screenManager = carContext.getCarService(ScreenManager::class.java)
screenManager.push(TripDetailScreen(carContext, trip.id))
}
.build()
listBuilder.addRow(row)
}
return ListTemplate.Builder()
.setTitle("Последние поездки")
.setSingleList(listBuilder.build())
.build()
}
}
Обратите внимание на setOnClickListener - все действия в автомобиле должны быть большими и легко нажимаемыми. Для навигации между экранами используем ScreenManager, полученный через carContext.getCarService().
В реальном приложении данные могут загружаться асинхронно, а сеть - отсутствовать. Для автомобиля нужно показывать понятные сообщения об ошибках и, возможно, кнопку повтора. Используйте MessageTemplate:
fun showError(message: String, onRetry: () -> Unit): Template {
val action = Action.Builder()
.setTitle("Повторить")
.setOnClickListener { onRetry() }
.build()
return MessageTemplate.Builder(message)
.addAction(action)
.build()
}
Если данные обновляются (например, при изменении в репозитории), автомобильный экран должен реагировать. В Screen можно подписаться на Flow с помощью carContext.lifecycleScope:
class TripsScreen(carContext: CarContext, repository: TripRepository) : Screen(carContext) {
init {
carContext.lifecycleScope.launch {
repository.tripsFlow.collect {
// При получении новых данных перерисовываем экран
invalidate()
}
}
}
// ... остальной код
}
Метод invalidate() вызывает повторный onGetTemplate, обновляя интерфейс.
Перед тем как запускать приложение на реальной машине, удобно использовать эмулятор DHU (Desktop Head Unit). Мы уже рассказывали, как его установить и настроить, в статье «Как запустить DHU для Android Auto». Запустите эмулятор, подключите к нему ваше приложение через Android Studio и проверьте, как выглядят экраны. Убедитесь, что все кнопки работают, нет вылетов и интерфейс не перегружен.
Для отладки можно использовать логи - Log.d будет виден в консоли Android Studio. Обратите особое внимание на работу с разрешениями: автомобильные приложения требуют ACCESS_SURFACE и другие права, которые могут быть не запрошены в телефоне.
Разработка под Android Auto сильно отличается от обычной мобильной. Вот несколько рекомендаций, которые помогут сделать приложение удобным и безопасным.
Водитель смотрит на экран с расстояния вытянутой руки и часто на ходу. Элементы управления должны быть крупными, контрастными и хорошо читаться даже при ярком солнечном свете. Избегайте мелких кнопок и тонких шрифтов. Car App Library автоматически подстраивает размеры, но вы можете влиять на них с помощью стилей.
Система Android Auto автоматически блокирует сложные операции во время движения (например, ввод длинного текста). Тем не менее, разработчик тоже должен заботиться о безопасности: не показывать видео, не требовать скролла длинных списков, отключать ненужные уведомления. Всё, что может отвлечь водителя дольше чем на секунду, должно быть упрощено или убрано.
Голос - основной способ взаимодействия за рулём. Полноценная поддержка голоса требует интеграции с Google Assistant или создания собственного VoiceInteractionService. Для простых приложений можно ограничиться встроенными возможностями: в Car App Library элементы списка автоматически получают голосовые метки (content description). Этого достаточно для базовой навигации. Если вы хотите реализовать сложные голосовые сценарии, обратитесь к документации Google.
Поддержка Android Auto - отличный кейс для портфолио. Он показывает, что вы умеете работать с современными платформами, учитываете контекст использования и соблюдаете требования безопасности.
Почему это ценят работодатели
Автомобильные приложения требуют понимания ограничений (размер экрана, ввод, безопасность) и умения адаптировать существующий код под новые условия. Это выделяет вас среди разработчиков, которые пишут только под телефоны. К тому же интеграция с Android Auto - это работа с проприетарными API Google, что тоже плюс.
Как описать этот проект в резюме
Добавьте в раздел «Опыт» или «Pet-проекты» строчку:
«Добавил поддержку Android Auto в существующее приложение-трекер поездок: создал автомобильный сервис, адаптировал UI под ограничения экрана в машине, организовал передачу данных через общий репозиторий, протестировал на эмуляторе DHU. Использовал Car App Library, Kotlin, архитектуру на основе ViewModel и репозиториев.»
Если проект был реальным и выложен на GitHub, обязательно укажите ссылку. Работодатель сможет зайти, посмотреть код и убедиться в качестве.
Подробнее об оформлении портфолио читайте в нашей статье «Как собрать первое портфолио мобильного Android-разработчика».
Мы рассмотрели, как за один рабочий день добавить поддержку Android Auto в готовое приложение. Вы узнали, как создать автомобильный сервис, объявить его в манифесте, построить первый экран и протестировать всё на эмуляторе DHU. Теперь ваше приложение может работать не только на телефоне, но и в автомобиле, а вы получили ценный опыт для портфолио.
Что изучить дальше
Задание для закрепления материала:
Добавьте второй экран в своё автомобильное приложение - например, детальный просмотр выбранного элемента. Используйте для передачи данных между экранами ScreenManager. Это поможет вам лучше понять навигацию в Car App Library.
Удачной разработки и безопасных дорог!