Пользователь нажимает «вниз» на пульте — фокус прыгает в конец списка, минуя кнопку «Избранное». Знакомая ситуация? Это классическая ошибка Focus Engine в Android TV приложениях. Мы проектируем мультимедийные приложения, в которых навигация предсказуема, плеер адаптируется под экран, а контент попадает в рекомендации Google TV. Разработка ведётся под ключ — от прототипа до публикации в Google Play. За 5 лет мы реализовали 12 OTT-проектов, накопленный опыт гарантирует качество и соответствие требованиям Google.
Как Android TV отличается от Google TV?
Google TV — надстройка над Android TV с другим лаунчером и требованиями к контенту. Приложение для Android TV может некорректно отображаться на Google TV из-за различий в обработке рекомендаций и deep link. Учитываем это на этапе проектирования, чтобы избежать проблем после релиза.
Как настроить D-pad навигацию в сложных макетах?
Главное отличие от мобильной разработки — пользователь управляет D-pad пульта. Фокус перемещается через Android Focus Engine, но вложенные горизонтальные RecyclerView внутри вертикального (Netflix-паттерн) ломают логику: при нажатии «вниз» фокус может перескочить в конец экрана. Решение — кастомный LinearLayoutManager с переопределённым onInterceptFocusSearch(). Без этого пользователь не добирается до нужного ряда.
Библиотека Leanback (androidx.leanback) предоставляет BrowseSupportFragment и RowsSupportFragment с нативной поддержкой D-pad, но она считается устаревшей. Jetpack Compose для TV (androidx.tv:tv-compose) предлагает TvLazyRow и TvLazyColumn с декларативным управлением фокусом. Для новых проектов выбираем Compose TV, для legacy — Leanback.
| Характеристика |
Leanback |
Compose TV |
| Архитектура |
Фрагменты, View |
Декларативная Compose |
| Навигация |
Автоматическая, ограниченная |
Кастомная через FocusRequester |
| Производительность |
Выше на старых устройствах |
Лучше на новых (API 24+) |
| Скорость разработки |
Ниже из-за шаблонов |
Выше, меньше кода |
| Поддержка Google TV |
Ограниченная |
Полная |
Как интегрировать ExoPlayer с адаптивным качеством?
androidx.media3:media3-exoplayer — стандарт для Android TV. Критично правильно настроить TrackSelector: выбор видео трека должен учитывать разрешение дисплея, а не просто брать максимальное — 4К на 1080p экране зря тратит пропускную способность. DRM Widevine L1 доступен на сертифицированных устройствах (SHIELD TV, Chromecast с Google TV). Проверяем уровень через MediaDrm.isCryptoSchemeSupported(WIDEVINE_UUID) и запрос securityLevel. Media3 документация рекомендует такой подход.
Интеграция с рекомендациями Google TV
Google TV отображает персонализированные рекомендации из приложений через API WatchNextPrograms. Требуется ContentProvider для заполнения прогресса просмотра, обновления статуса и удаления завершённых программ. Fire TV использует другой механизм — App-to-App Communication через Intent для deep link в контент.
Как проходит разработка: пошагово
- Анализ требований к контенту, монетизации и целевой платформе.
- Проектирование навигации и focus-менеджмента.
- Интеграция ExoPlayer с кастомными настройками треков и DRM.
- Реализация рекомендаций Google TV (WatchNext Programs).
- Тестирование на 5+ устройствах (NVIDIA Shield, Chromecast с Google TV, Xiaomi Mi Box, TCL TV, Sony Bravia).
- Подготовка графики для лаунчера и иконок.
- Сборка и публикация в Google Play с соблюдением Android TV developer guide.
- Техническая поддержка после релиза (1 месяц).
Сертификация и публикация в Google Play
Приложение публикуется с <uses-feature android:name="android.software.leanback"/> и <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>. Последнее обязательно — без него Play Store не покажет приложение на TV. Google проверяет: навигация доступна с D-pad, нет зависимостей от тача, корректно обрабатываются KEYCODE_BACK и KEYCODE_DPAD_*.
Что входит в работу
- Исходный код с комментариями и документация по сборке.
- Конфигурация CI/CD (GitHub Actions, Fastlane) для автоматической публикации в TestFlight и Google Play.
- Доступы к консолям разработчика (App Store Connect, Google Play Console).
- Тестовый отчёт по 5 устройствам с разными версиями ОС.
- Обучение команды заказчика по работе с админкой контента.
- Пост-релизная поддержка в течение 1 месяца (исправление критических багов).
Типичные ошибки при разработке
- Игнорирование Focus Engine — пользователь не может добраться до кнопок.
- Отсутствие обработки KEYCODE_BACK — приложение не закрывается.
- Неправильная конфигурация TrackSelector — буферизация 4K на 1080p экране.
- Пропуск метаданных для Google TV — нет рекомендаций.
- Забытая зависимость android.hardware.touchscreen:false — приложение не видно.
Сроки и стоимость
| Тип приложения |
Сроки |
| Информационное на Leanback |
от 5 до 9 недель |
| VOD с DRM, рекомендациями, офлайном |
от 12 до 20 недель |
Стоимость рассчитывается индивидуально после анализа контента и монетизации. Бесплатно оценим ваш проект. Свяжитесь с нами, чтобы обсудить детали. Получите консультацию по вашему проекту.
Разработка виджетов, App Clips и Live Activities: точки входа вне приложения
Мы знаем, что пользователь видит приложение не только внутри него. Виджет на домашнем экране, живой счёт матча в Dynamic Island, мини‑опыт без установки — всё это отдельные точки входа, которые мы реализуем с учётом ограничений платформы. За 5 лет мы разработали более 50 расширений для мобильных приложений — от простых информационных виджетов до App Clips с платёжными сценариями, экономя клиентам до 30% времени на повторных входах.
Разработка виджетов WidgetKit: почему нельзя просто «добавить виджет»
WidgetKit работает через Timeline Provider — виджет не живёт в памяти постоянно, а запрашивает снимки данных заранее. Самая частая ошибка: разработчик пытается показать данные в реальном времени через URLSession прямо из getTimeline(). Apple этого не запрещает, но при агрессивном обновлении система начинает троттлить запросы, и виджет зависает на устаревших данных.
Правильный подход: основное приложение обновляет данные через WidgetCenter.shared.reloadTimelines(ofKind:) — после получения пуш-уведомления или при возврате пользователя в foreground. Виджет читает данные из shared App Group container через UserDefaults(suiteName:) или файлового хранилища. Никаких прямых сетевых запросов в провайдере в продакшне.
В новейших версиях iOS появился AppIntent-based interactive widget — кнопки и тогглы прямо на виджете без открытия приложения. Реализуется через Button(intent:) в SwiftUI-разметке виджета. Работает только для простых действий; сложная логика должна переходить в приложение через widgetURL.
Как Live Activities меняют пользовательский опыт?
Live Activities — механизм для отображения живых данных на Lock Screen и в Dynamic Island (iPhone 14 Pro+). Запускаются через ActivityKit, обновляются через push-уведомления типа liveactivity с полезной нагрузкой до 4KB.
Архитектурно это отдельный SwiftUI-таргет с двумя представлениями: компактным (Dynamic Island) и развёрнутым (Lock Screen). Данные передаются через ActivityAttributes — строго типизированную структуру. Динамическая часть — ContentState, статическая (не меняется за время активности) — в ActivityAttributes напрямую.
Типичная проблема: Live Activity не обновляется на устройстве, хотя push отправляется. Причина — приложение не имеет permission на background push или apns-push-type выставлен неправильно. В production нужен apns-push-type: liveactivity и токен из activity.pushToken. Согласно документации Apple, без корректного push-токена Activity не получит обновлений.
Когда использовать App Clips, а когда Instant Apps?
App Clips (iOS) и Instant Apps (Android) решают похожую задачу — дать пользователю функциональность без установки полного приложения. Но реализация принципиально разная.
App Clip — отдельный таргет в Xcode, максимум 15MB, запускается через NFC-метку, QR-код, Safari Smart App Banner или ссылку в Messages. Доступ к данным ограничен: нет Keychain sharing с основным приложением без явной настройки, нет доступа к HealthKit, нет push-уведомлений (только ephemeral). App Clip Card настраивается в App Store Connect, и ошибки в метаданных — частая причина отказа в ревью.
Android Instant Apps строятся на модульной архитектуре: приложение делится на feature-модули, каждый из которых может быть загружен отдельно через Play Feature Delivery. Instant App — это feature-модуль с <dist:module dist:instant="true">. Ограничение — не более 15MB суммарно для instant delivery.
Сравнение показывает, что App Clips выигрывают в сценариях с оплатой благодаря интеграции с Apple Pay — конверсия выше на 20% по сравнению с Instant Apps в аналогичных кейсах. Instant Apps лучше подходят для игровых демо и сервисов, где требуется быстрый доступ к функциям через Google Search.
| Параметр |
App Clips |
Instant Apps |
| Макс. размер |
15 MB |
15 MB |
| Триггеры запуска |
NFC, QR, URL, Safari |
URL, Google Search, Play Store |
| Общий Keychain |
Через App Group |
Через SharedPreferences/Keystore |
| Рекомендуемый сценарий |
Оплата, посадочный, демо |
Игровое демо, разовые сервисы |
Что входит в работу?
-
Аудит текущей архитектуры: определяем, какие точки входа нужны вашему приложению — виджет, Live Activity, App Clip, Instant App.
-
Прототипирование: визуальная модель расширения с учётом гайдлайнов платформы (Apple HIG, Material Design).
-
Разработка: реализация на Swift (iOS) или Kotlin (Android) с использованием WidgetKit, ActivityKit, App Clip API, Play Feature Delivery.
-
Интеграция: настройка App Group, Keychain sharing, push-сертификатов, provisioning profile.
-
Тестирование: на реальных устройствах (iPhone, iPad, Android) и в симуляторах. Для Live Activities — тест через
xcrun simctl push.
-
Публикация: подготовка метаданных для App Store Connect (App Clip Card) и Google Play Console (Instant App configuration).
-
Документация и обучение: описание архитектуры, инструкции по обновлению виджетов, troubleshooting push-уведомлений.
Процесс работы
-
Аналитика: какие функции приложения реально нужны вне него, и какой механизм подходит. Виджет с прогнозом — WidgetKit. Трекинг доставки в реальном времени — Live Activity. Оплата на кассе — App Clip.
-
Проектирование: выбор стека, схемы обновления данных (Timeline, push), UI-макеты для компактного и развёрнутого представления.
-
Реализация: написание кода на Swift/Kotlin, настройка App Group, push-сертификатов, тестовых схем.
-
Тест: каждое расширение тестируется изолированно. WidgetKit-рендеринг проверяется через Xcode Widget Gallery, Live Activities — через симулятор с принудительной отправкой push.
-
Деплой: публикация в сторах, мониторинг метрик (частота обновлений, количество запусков App Clip).
Сроки ориентировочно
| Тип расширения |
Срок (рабочие дни) |
| Простой информационный виджет |
от 5 до 10 |
| Интерактивный виджет (AppIntent) |
от 10 до 15 |
| Live Activity с push |
от 10 до 20 |
| App Clip с оплатой |
от 20 до 30 |
| Instant App (Android) |
от 15 до 25 |
Стоимость рассчитывается индивидуально после аудита. Оценка даётся в течение 2 рабочих дней.
Типичные ошибки при разработке расширений
-
Слишком частое обновление виджета — приводит к троттлингу и пустому состоянию. Рекомендуем интервал не менее 15 минут (см. Apple Human Interface Guidelines в WidgetKit documentation).
-
Игнорирование shared container — виджет не видит данные, потому что использует свой
UserDefaults, а не App Group.
-
Отсутствие fallback для Live Activities — если push не доставлен, пользователь видит устаревшие данные. Нужен механизм периодического опроса через
Activity.update с pushType: nil.
-
Неправильные метаданные App Clip Card — частая причина отклонения в App Store Review. Например, некорректный URL или недостающий значок.
Свяжитесь с нами, чтобы оценить, какое расширение подходит вашему приложению. Закажите аудит текущих точек входа — мы найдём неочевидные сценарии для виджетов и App Clips. Получите консультацию инженера по архитектуре уже сегодня.