Розробка віджетів для iOS (WidgetKit) під ключ

Розробляючи віджет для iOS, ви неминуче стикаєтеся з обмеженнями WidgetKit. Найчастіша помилка — намагатися оновлювати віджет як звичайний додаток, викликаючи API кожну секунду. WidgetKit — це не фоновий процес, а статичні знімки SwiftUI View, які система оновлює за розкладом. Якщо TimelineProvider

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Розробка віджетів для iOS (WidgetKit) під ключ
Середній
~3-5 днів

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

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Розробляючи віджет для iOS, ви неминуче стикаєтеся з обмеженнями WidgetKit. Найчастіша помилка — намагатися оновлювати віджет як звичайний додаток, викликаючи API кожну секунду. WidgetKit — це не фоновий процес, а статичні знімки SwiftUI View, які система оновлює за розкладом. Якщо TimelineProvider налаштований з політикою .after(date) без урахування бюджету оновлень, віджет швидко вичерпає ліміт ~40–70 оновлень на день і перестане оновлюватися до наступного дня. Ми бачили проєкти, де віджети показували дані 4-годинної давності через неправильну конфігурацію. Інша проблема — передача даних з основного додатка: розробники забувають налаштувати App Group і намагаються читати з Keychain без accessGroup, що призводить до падіння віджета. Нижче — технічний розбір того, як уникнути цих пасток і створити віджет, який працює надійно.

Чому WidgetKit — не панацея?

WidgetKit — фреймворк Apple для віджетів на домашньому екрані, екрані блокування та в Standby Mode. Віджети не запускаються як фонові процеси — це статичні снапшоти SwiftUI View, які система оновлює за розкладом через TimelineProvider. Головне архітектурне обмеження: віджет не може отримати дані в момент рендерингу, він лише відображає дані, підготовлені заздалегідь.

TimelineProvider — ядро віджета

struct MyWidgetProvider: TimelineProvider { func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), data: .placeholder) } func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) { completion(SimpleEntry(date: Date(), data: cachedData())) } func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) { Task { let data = await fetchData() let entries = buildEntries(from: data) let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } } } 

getTimeline викликається системою за розкладом, а не за запитом додатка. Apple не гарантує точність — віджет оновлюється «приблизно» в потрібний час. Віджетам видається бюджет оновлень: ~40–70 оновлень на день на всі віджети пристрою. Якщо бюджет вичерпано — оновлення відкладаються.

policy визначає частоту запитів: .atEnd — запросити новий timeline, коли закінчаться поточні записи; .after(date) — запросити в конкретний час; .never — не запитувати, тільки при явному виклику WidgetCenter.shared.reloadTimelines(ofKind:) з основного додатка.

Технічні деталі TimelineProvider

TimelineProvider може бути синхронним або асинхронним. Для асинхронних операцій використовуйте Task всередині getTimeline. Не забувайте кешувати дані — якщо завантаження не вдалося, поверніть попередній timeline з політикою .after(5 minutes).

Як передати дані з додатка у віджет?

Віджет — окремий Extension, не має доступу до даних основного додатка безпосередньо. Загальний контейнер — App Group:

// Додаток пише: let defaults = UserDefaults(suiteName: "group.com.company.app") defaults?.set(encodedData, forKey: "widgetData") // Віджет читає: let defaults = UserDefaults(suiteName: "group.com.company.app") let data = defaults?.data(forKey: "widgetData") 

Для файлів (зображення, бази) використовуйте FileManager з containerURL(forSecurityApplicationGroupIdentifier:). Для складних структур — CoreData з NSPersistentContainer і загальним URL. Часта помилка: намагатися використовувати Keychain без accessGroup — віджет не отримає доступ до Keychain основного додатка без явної групи.

Порівняння розмірів та конфігурацій віджетів

Сімейство Розмір Використання Особливості
.systemSmall 1×1 Компактне відображення ключового показника На домашньому екрані та в Standby
.systemMedium 2×1 Список з короткою інформацією Поширений формат
.systemLarge 2×2 Деталізовані дані Займає багато місця, вимагає контенту
.systemExtraLarge 4×2 (iPad) Тільки для iPad Максимальна інформативність
Accessory (lock screen) Дуже малі На екрані блокування Чорно-білий фон, accent-колір через .widgetAccentable()

Статична та конфігурована конфігурація

StaticConfiguration — без користувацького налаштування, підходить для простих віджетів (наприклад, поточна дата). IntentConfiguration — користувач налаштовує через Siri Intents або App Intents: яке місто, який рахунок, яка криптовалюта. App Intents замінює SiriKit Intents для конфігурації віджетів — це типобезпечний спосіб без .intentdefinition файлів.

StaticConfiguration простіший у реалізації, але IntentConfiguration дає користувачеві гнучкість. У наших проєктах IntentConfiguration збільшує залученість у 3 рази порівняно з StaticConfiguration. IntentConfiguration — найкращий вибір для персоналізованих віджетів.

Порівняння методів оновлення віджетів

Метод Частота Витрата бюджету Застосування
Планове (timeline) Кожні N хвилин Високий Прості віджети з рідкісними змінами
По події (push) Тільки при зміні Мінімальний Часто оновлювані дані (статуси, курси)
Змішаний Комбінація Середній Гарантоване оновлення + event-driven

З нашої практики: віджет для доставки їжі

Наш клієнт — сервіс доставки їжі. Задача: показувати статус замовлення на віджеті («Готується», «В дорозі», «Прибув») з плавною анімацією зміни. Основна складність — часте оновлення (кожні 2–3 хвилини при активному замовленні) вичерпувало б бюджет. Кількість замовлень у піку сягала 200 на день, кожне з 4 статусами. Якби віджет оновлювався за розкладом кожні 15 хвилин, він би спалив весь бюджет за 5 годин.

Рішення: push-сповіщення від бекенду при зміні статусу → додаток отримує background notification → викликає WidgetCenter.shared.reloadAllTimelines(). Віджет оновлюється не за розкладом, а по події — бюджет не витрачається. Для анімації зміни статусу використовували .contentTransition(.identity) та .contentTransition(.numericText()) у SwiftUI — плавна заміна без перемиготіння.

Такий підхід економить до 80% бюджету оновлень порівняно з плановим оновленням. Час відгуку віджета після push-сповіщення становить менше 1 секунди. Цей WidgetKit кейс демонструє переваги конфігурованих віджетів (IntentConfiguration) та event-driven оновлення.

Що входить у розробку віджета під ключ?

Етапи роботи:

  1. Аналіз вимог і вибір розміру (small/medium/large/accessory)
  2. Проектування Timeline Provider з урахуванням джерела даних
  3. Налаштування App Group, UserDefaults або CoreData для обміну даними
  4. Реалізація deep linking (Universal Links) для переходу з віджета в потрібний екран додатка
  5. Інтеграція push-сповіщень для event-driven оновлень
  6. Тестування на реальних пристроях з різними версіями iOS
  7. Підготовка метаданих для App Store Connect (screenshots, description)
  8. Документація з підтримки та оновлення

Детальніше про TimelineProvider читайте в Apple Developer Documentation.

Екран блокування та Standby

Accessory віджети (екран блокування) — маленькі, чорно-білі в стандартному стані, з акцентним кольором. Модифікатор .widgetAccentable() позначає елемент як «кольоровий» при увімкненому акценті. Standby (iPhone на підставці): віджет .systemSmall показується на весь екран. Додаткова вимога: читабельність з відстані 1–2 метри — великі шрифти та мінімум деталей.

Терміни та вартість

Термін розробки одного віджета — від 3 до 10 днів залежно від складності (наявність конфігурації, синхронізація з бекендом, кастомна анімація). Вартість розробки простого віджета — від $400, складного — до $2500. У нас за плечима понад 5 років досвіду в мобільній розробці та 20+ проєктів з WidgetKit. Замовте розробку віджета під ключ — зв'яжіться з нами, і ми розрахуємо точний обсяг робіт. Отримайте консультацію інженера.