Разработка виджетов для Android: RemoteViews, Glance и FCM

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Разработка виджетов для Android: RemoteViews, Glance и FCM
Средний
~3-5 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    743
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    562

Вы разработали виджет с обновлением раз в 30 минут, но пользователи жалуются на устаревшие данные. Курсы валют меняются каждую минуту, статус заказа — в реальном времени. Стандартный updatePeriodMillis с минимумом 30 минут не подходит. Решение — использовать WorkManager для периодических задач или push-уведомления от сервера. Наш опыт — 5+ лет разработки виджетов для Android, более 50 проектов в Google Play. Например, в одном проекте для торговой платформы мы заменили pull-обновление на push через FCM, что сократило задержку с 30 минут до 2 секунд. Пользователи сразу заметили разницу. Мы создаём виджеты любой сложности: от информационных панелей до интерактивных коллекций с мгновенными обновлениями. Гарантируем стабильность и соответствие гайдлайнам. Получите консультацию по вашей задаче.

Как обновлять виджет быстрее 30 минут?

Система разрешает android:updatePeriodMillis не меньше 1800000 мс. Для более частых обновлений используйте WorkManager с PeriodicWorkRequest (минимум 15 минут, установлено в API) или AlarmManager. Внутри WorkManager вызывайте AppWidgetManager.updateAppWidget(). Для push-обновлений — FirebaseMessagingService.onMessageReceived с прямым вызовом updateAppWidget. WorkManager автоматически учитывает Doze Mode и Standby Buckets, чтобы батарея не страдала. Вот сравнение подходов:

Способ обновления Минимальный интервал Рекомендация
updatePeriodMillis 30 минут Только для данных с низкой частотой изменений
WorkManager 15 минут Для регулярных данных (погода, курсы)
Push (FCM) Мгновенно Для событийных уведомлений (статус заказа, сообщения)

Для реализации push-обновлений добавьте серверную интеграцию, отправляющую данные на устройство. Мы используем FCM — push доходят даже при свёрнутом приложении.

Пример реализации обновления через WorkManager
class WidgetUpdateWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        val widgetManager = AppWidgetManager.getInstance(applicationContext)
        val widgetIds = widgetManager.getAppWidgetIds(ComponentName(applicationContext, MyWidget::class.java))
        val views = buildRemoteViews(applicationContext)
        widgetManager.updateAppWidget(widgetIds, views)
        return Result.success()
    }
}

Почему RemoteViews ограничивает интерактивность?

Android-виджет исполняется в процессе лаунчера, поэтому доступен только RemoteViews. RemoteViews ограничен базовыми View: TextView, ImageView, Button, LinearLayout, RelativeLayout, FrameLayout, GridLayout, ListView, GridView, StackView. Запрещены RecyclerView, ConstraintLayout (до API 31), кастомные View, WebView. Для отображения списков используйте ListView или GridView с RemoteViewsFactory. Начиная с Android 12 (API 31) добавились CheckBox, RadioButton, Switch. Важно: все элементы только через PendingIntent для обработки нажатий — assignOnClick — прямое обращение к View не работает. Типичная ошибка — попытка установить onClickListener напрямую; это невозможно. Используйте setOnClickPendingIntent или setPendingIntentTemplate для коллекций.

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

Библиотека Glance предлагает Compose-подобный синтаксис, скрывая ручное создание RemoteViews. Вы пишете декларативно: Column, Text, Button. Glance автоматически генерирует RemoteViews. Это снижает шанс ошибок и ускоряет разработку. Однако Glance пока поддерживает не все компоненты: например, LazyColumn нет, используйте Column с фиксированным числом строк. Состояние управляется через GlanceStateDefinition и updateAppWidgetState. Для нового проекта с minSdkVersion 23+ — это лучший выбор. Вот минимальный пример:

class MyGlanceWidget : GlanceAppWidget() {
    @Composable
    override fun Content() {
        val data = currentState<MyWidgetData>()
        Column(modifier = GlanceModifier.fillMaxSize().background(Color.White)) {
            Text(text = data.title, style = TextStyle(fontSize = 16.sp))
            Button(text = "Обновить", onClick = actionRunCallback<RefreshAction>())
        }
    }
}
Характеристика RemoteViews Glance
Синтаксис Императивный (XML + Java/Kotlin) Декларативный (Compose-подобный)
Вероятность ошибок Выше Ниже
Поддержка коллекций ListView/GridView Column (фиксированное число строк)
Минимальный API 17 (с учётом ограничений) 23

AppWidgetProvider и обработка обновлений

AppWidgetProvider — BroadcastReceiver, который получает обновления. В onUpdate() создайте RemoteViews и вызовите updateAppWidget(). Типичная реализация:

class MyWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        appWidgetIds.forEach { widgetId ->
            val views = buildRemoteViews(context)
            appWidgetManager.updateAppWidget(widgetId, views)
        }
    }
}

Для виджетов с данными из интернета используйте фоновый загрузчик в onReceive или через WorkManager. Никогда не блокируйте onUpdate — это UI-поток. Обрабатывайте ошибки загрузки: показывайте заглушку (например, TextView с текстом «Ошибка загрузки») и планируйте повторную попытку через WorkManager.

Работа с коллекциями через RemoteViewsFactory

ListView или GridView в виджете требуют RemoteViewsFactory. Фабрика создаёт RemoteViews для каждого элемента. Нажатия на элементы реализуются через setOnClickFillInIntent и setPendingIntentTemplate. Шаблон — это PendingIntent, который будет запускаться с fill-данными. Пример:

class WidgetListFactory(private val context: Context) : RemoteViewsService.RemoteViewsFactory {
    private var items: List<WidgetItem> = emptyList()

    override fun onDataSetChanged() {
        items = loadDataFromSharedPrefs(context)
    }

    override fun getViewAt(position: Int): RemoteViews {
        val item = items[position]
        return RemoteViews(context.packageName, R.layout.widget_list_item).apply {
            setTextViewText(R.id.item_title, item.title)
            val fillIntent = Intent().putExtra("item_id", item.id)
            setOnClickFillInIntent(R.id.item_container, fillIntent)
        }
    }
}

Важно: onDataSetChanged() вызывается в фоновом потоке, но сам RemoteViewsFactory может быть закэширован. Сбрасывайте кэш при необходимости.

Конфигурация виджета пользователем

AppWidgetConfigure Activity открывается при добавлении виджета. Пользователь выбирает параметры (город, тему, частоту обновления). После выбора обязательно вызвать:

setResult(Activity.RESULT_OK, intent.putExtra(EXTRA_APPWIDGET_ID, widgetId))

Без этого виджет не добавится. В Glance конфигурацию запускайте через GlanceAppWidgetManager().startConfigureActivityIntent.

Этапы разработки виджета

  1. Анализ требований: определение функциональности, частоты обновлений, целевых размеров (2x2, 4x2, 4x4).
  2. Проектирование макета: выбор между RemoteViews и Glance, создание XML-макета или Compose-интерфейса.
  3. Реализация AppWidgetProvider: написание логики обновлений с WorkManager или FCM.
  4. Интеграция данных: подключение к API, базе данных (Room) или SharedPreferences.
  5. Тестирование: на эмуляторах и реальных устройствах, включая Doze Mode.
  6. Публикация: подготовка метаданных, code signing, размещение в Google Play.

Что входит в разработку

  • Макет RemoteViews с адаптацией под размеры (2x2, 4x2, 4x4).
  • AppWidgetProvider с поддержкой обновлений (WorkManager, FCM).
  • Конфигурационный экран при необходимости.
  • Интеграция с базой данных (Room) или сетевым API.
  • Публикация в Google Play с метаданными, настройка code signing и provisioning profile.
  • Документация и исходные коды.

Сроки и стоимость

Срок разработки одного виджета с конфигурацией и регулярными обновлениями — от 3 до 5 дней. Если требуется коллекция с push-обновлениями — до 1 недели. Стоимость рассчитывается индивидуально: отправьте техническое задание для оценки. Получите консультацию по архитектуре — мы поможем выбрать стек (RemoteViews или Glance) и избежать типичных проблем с производительностью. Закажите разработку виджета уже сегодня — свяжитесь с нами для начала работы. Оптимизируйте бюджет — мы предлагаем гибкие условия.

Типичные ошибки при разработке виджетов

  • Использование updatePeriodMillis для данных, требующих частого обновления. Переходите на WorkManager или FCM.
  • Блокировка onUpdate() долгими операциями. Все фоновые задачи выносите в WorkManager.
  • Игнорирование Doze Mode: используйте WorkManager с учётом Standby Buckets.
  • Неправильная обработка конфигурации: не забывайте вызывать setResult.
  • Отсутствие заглушек при ошибках загрузки данных.

Мы реализуем виджеты на Java или Kotlin, включая гибридные решения. Более 50 успешных проектов подтверждают наш опыт. Свяжитесь с нами для оценки вашего проекта.

Разработка виджетов, 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-уведомлений.

Процесс работы

  1. Аналитика: какие функции приложения реально нужны вне него, и какой механизм подходит. Виджет с прогнозом — WidgetKit. Трекинг доставки в реальном времени — Live Activity. Оплата на кассе — App Clip.
  2. Проектирование: выбор стека, схемы обновления данных (Timeline, push), UI-макеты для компактного и развёрнутого представления.
  3. Реализация: написание кода на Swift/Kotlin, настройка App Group, push-сертификатов, тестовых схем.
  4. Тест: каждое расширение тестируется изолированно. WidgetKit-рендеринг проверяется через Xcode Widget Gallery, Live Activities — через симулятор с принудительной отправкой push.
  5. Деплой: публикация в сторах, мониторинг метрик (частота обновлений, количество запусков 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. Получите консультацию инженера по архитектуре уже сегодня.