Розробка віджетів для 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%. Ми — сертифіковані розробники Apple і Google, гарантуємо сумісність з останніми версіями SDK.

Розробка віджетів WidgetKit: чому не можна просто «додати віджет»

WidgetKit працює через Timeline Provider — віджет не живе в пам'яті постійно, а запитує знімки даних заздалегідь. Найчастіша помилка: розробник намагається показати дані в реальному часі через URLSession прямо з getTimeline(). Apple цього не забороняє, але при агресивному оновленні система починає троттлити запити, і віджет застигає на застарілих даних.

Правильний підхід: основний додаток оновлює дані через WidgetCenter.shared.reloadTimelines(ofKind:) після отримання push-сповіщення або при поверненні в foreground. Віджет читає дані з shared App Group контейнера через 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. Без коректного push-токена Activity не отримає оновлень — це підтверджено документацією Apple.

Коли використовувати 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. Отримайте консультацію інженера з архітектури вже сьогодні. Гарантуємо проходження App Store Review з першого разу — наш досвід підтверджений десятками успішних публікацій.