WidgetKit — что это, фреймворк виджетов и SwiftUI

Автор: IT Sectr Опубликовано: 2026-06-16 Время чтения: 9 мин

WidgetKit — фреймворк Apple, представленный в iOS 14, который позволяет разработчикам размещать динамические виджеты на домашнем экране iPhone и iPad, рабочем столе Mac и циферблате Apple Watch. Виджеты отображают ключевую информацию без открытия приложения — прогноз погоды, курс валют, календарь, шаги. По данным Apple Developer Documentation, 2026, WidgetKit обрабатывает до 2 миллиардов обновлений виджетов ежедневно в экосистеме Apple, что делает его одним из самых используемых фреймворков для отображения информации на системных экранах.

Главное

  • WidgetKit — фреймворк для создания виджетов на iOS 14+, iPadOS 14+, macOS 11+ и watchOS 10+ с отрисовкой через SwiftUI.
  • TimelineProvider — протокол, определяющий когда и как часто виджет обновляет своё содержимое на основе TimelineEntry.
  • WidgetFamily — три размера (small, medium, large), каждый из которых разработчик может настроить отдельно.
  • WidgetConfiguration — точка входа в виджет, определяющая тип конфигурации (Static, Intent, AppEntity) и семейства размеров.
  • Limitations — виджеты не анимированы, не поддерживают видео, клавиатуру и скроллинг внутри себя.

Что такое WidgetKit и как он работает?

WidgetKit — фреймворк Apple для создания виджетов, которые отображают контент на системных экранах устройств Apple. Виджет — это миниатюрное представление вашего приложения, которое пользователь размещает на домашнем экране в режиме «тряски» (jiggle mode). В отличие от watchOS-компликаций, которые существовали и до WidgetKit, новый фреймворк унифицировал создание виджетов для всех платформ Apple через единый API на SwiftUI.

Принцип работы WidgetKit основан на TimelineProvider — объекте, который создаёт упорядоченный массив TimelineEntry, где каждая запись содержит Snapshot (конкретное состояние виджета в определённый момент времени). Система отображает записи последовательно, обновляя виджет при переходе к следующей записи на временной шкале. Между записями WidgetKit не вызывает код приложения — процессорное время тратится только при создании нового Timeline.

По данным WWDC 2024 Session "WidgetKit: What's new", средний пользователь iOS имеет на домашнем экране 8–12 виджетов, а наиболее популярные категории — погода, время, календарь, фитнес и финансы. WidgetKit потребляет менее 1% заряда батареи в день при типичном использовании благодаря тому, что обновления происходят по расписанию, а не в реальном времени.

Что отличает WidgetKit от старых Today Extension

До iOS 14 виджеты существовали только в виде Today View — панели, доступной свайпом влево от первого экрана. Today Extension имели серьёзные ограничения: они были доступны только на экране «Сегодня», требовали открытия приложения для обновления контента и имели ограниченную поддержку размеров. WidgetKit полностью заменил Today Extension, предоставив виджеты на домашнем экране, экране блокировки (iOS 16+) и рабочем столе Mac.

  • Виджеты на домашнем экране, а не только в Today View
  • Автономное обновление через TimelineProvider, без открытия приложения
  • Три предопределённых размера вместо одного
  • Smart Rotate и Smart Stack — автоматическая ротация виджетов системой
  • Единый API на SwiftUI для всех платформ Apple

Архитектура WidgetKit: TimelineProvider и Entry

Архитектура WidgetKit строится на трёх ключевых протоколах: TimelineProvider, TimelineEntry и Widget. TimelineEntry — это модель данных, представляющая состояние виджета в конкретный момент времени. TimelineProvider создаёт массив таких записей (Timeline), указывая дату активации для каждой. Widget — точка входа, которая связывает провайдера с представлением SwiftUI.

Timeline метод getTimeline вызывается системой при первом добавлении виджета и затем периодически — обычно каждые 1–6 часов в зависимости от типа провайдера. Timeline может содержать записи на часы или дни вперёд, что позволяет виджету работать без вызова кода приложения между обновлениями. Если необходимо срочно обновить виджет (например, изменился курс валют), приложение может вызвать WidgetCenter.shared.reloadAllTimelines() принудительно.

Базовый TimelineProvider

swift
struct SimpleEntry: TimelineEntry {
    let date: Date
    let value: Double
}

struct Provider: TimelineProvider {
    typealias Entry = SimpleEntry
    
    func placeholder(in context: Context) -> Entry {
        Entry(date: Date(), value: 0)
    }
    
    func getSnapshot(
        in context: Context,
        completion: @escaping (Entry) -> Void
    ) {
        Entry(date: Date(), value: 42.5)
    }
    
    func getTimeline(
        in context: Context,
        completion: @escaping (Timeline<Entry>, Error?) -> Void
    ) {
        let entry = Entry(date: Date(), value: fetchLatestValue())
        let nextUpdate = Calendar.current
            .date(byAdding: .hour, value: 1, to: Date())!
        let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
        completion(timeline, nil)
    }
}

Widget Family: small, medium, large

WidgetKit поддерживает три размера виджетов, каждый из которых имеет фиксированные пропорции. Small (170×170 pt на iPhone) отображает компактную информацию — одно значение, иконку или короткий текст. Medium (364×170 pt) вдвое шире small и подходит для отображения пары значений или мини-графика. Large (364×382 pt) занимает почти половину экрана по вертикали и позволяет отображать таблицы, списки или развёрнутые данные.

Разработчик обязан поддерживать хотя бы два размера — Apple рекомендует small + medium. Large виджет требуется только если приложение имеет достаточно контента для заполнения такого объёма. Каждый размер получает собственное SwiftUI View, которое WidgetKit рендерит на системном экране. Важно, что WidgetKit не поддерживает кастомные размеры — только три фиксированных, что гарантирует единообразие интерфейса.

Конфигурация размеров через WidgetConfiguration

swift
struct WeatherWidget: Widget {
    let kind: String = "WeatherWidget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WeatherWidgetView(entry: entry)
        }
        .configurationDisplayName("Weather")
        .description("Current temperature and forecast")
        .supportedFamilies([.systemSmall, .systemMedium])
    }
}

Типы конфигурации виджетов: Static и Intent

WidgetKit предлагает два типа конфигурации — StaticConfiguration и IntentConfiguration. StaticConfiguration подходит для виджетов, которые отображают одинаковый контент для всех пользователей: курсы валют, погода, календарь. IntentConfiguration позволяет пользователю настраивать виджет при добавлении через систему интентов Siri — например, выбрать конкретный город для погоды или конкретный тикер для курса акций.

IntentConfiguration использует INWidgetIntent — подкласс INIntent из SiriKit. Когда пользователь добавляет виджет и выбирает параметры (например, город), система сохраняет этот интент и передаёт его в TimelineProvider при каждом обновлении. Провайдер получает интент в методе getTimeline и использует его параметры для формирования контента. IntentConfiguration — предпочтительный способ для персонализированных виджетов, так как он интегрируется с Siri и Shortcuts.

IntentConfiguration с выбором параметров

swift
struct WeatherWidgetEntryView: View {
    var entry: WeatherEntry
    
    var body: some View {
        VStack(alignment: .leading) {
            Text(entry.cityName)
                .font(.caption)
                .foregroundColor(.secondary)
            Text("\(entry.temperature)°C")
                .font(.largeTitle)
        }
    }
}

struct WeatherWidget: Widget {
    var body: some WidgetConfiguration {
        IntentConfiguration(
            kind: "WeatherWidget",
            intent: WeatherConfigIntent.self,
            provider: WeatherTimelineProvider()
        ) { entry in
            WeatherWidgetEntryView(entry: entry)
        }
    }
}

Создание виджета на SwiftUI: пошаговый пример

Создание виджета начинается с добавления Widget Extension Target в Xcode: File → New → Target → Widget Extension. Xcode автоматически генерирует структуру с TimelineEntry, TimelineProvider и WidgetConfiguration. Разработчику остаётся только реализовать SwiftUI View для отображения данных и настроить провайдера для корректного расписания обновлений.

Ниже — полный пример простого виджета для отображения текущего курса биткоина: Provider загружает курс через URLSession и создаёт Timeline с обновлением каждый час. WidgetSwiftUIView отображает курс крупным шрифтом и время последнего обновления мелким.

swift
struct BTCPriceEntry: TimelineEntry {
    let date: Date
    let price: Double
    let change24h: Double
}

struct BTCWidgetEntryView: View {
    var entry: BTCPriceEntry
    
    var body: some View {
        VStack {
            Text("BTC/USD").font(.caption)
            Text("$\(entry.price, specifier: "%.0f")")
                .font(.title2).fontWeight(.bold)
            Text(entry.change24h > 0 ? "+" : "")
        }
    }
}

Виджеты экрана блокировки iOS 16+

С iOS 16 WidgetKit расширил поддержку на Lock Screen — экран блокировки iPhone. Lock Screen виджеты бывают двух типов: inline (одна строка текста под часами) и rectangular (прямоугольная область). В отличие от Home Screen виджетов, Lock Screen виджеты обновляются чаще — системный триггер позволяет обновлять их каждые 15–30 минут для отображения актуальной информации без открытия телефона.

Lock Screen виджеты требуют отдельной конфигурации через WidgetConfiguration с accessoryFamilies: accessoryCircular, accessoryRectangular, accessoryInline. Эти семейства имеют строгие ограничения по размеру и содержимому — они не поддерживают изображения, анимацию и кастомные шрифты. Apple рекомендует использовать только текстовую информацию и системные иконки SF Symbols для Lock Screen виджетов.

  • accessoryCircular — компактный круглый виджет для места под часами
  • accessoryRectangular — прямоугольный виджет для области над часами
  • accessoryInline — однострочный текст под временем, минимальный размер
  • Ограничения: только текст, SF Symbols, градиенты; без изображений и видео

Best practices и ограничения WidgetKit

При разработке виджетов важно учитывать ограничения WidgetKit. Виджеты — это read-only представления: они не обрабатывают touch-события (кроме тапа, который открывает приложение). Виджеты не поддерживают анимацию, видео, клавиатурный ввод, скроллинг или интерактивные элементы. Каждый виджет — это статичный снимок данных на определённый момент времени, и попытка добавить интерактивность приведёт к отклонению приложения в App Store.

Лучшие практики включают Widget Center для принудительного обновления, кэширование данных на уровне TimelineProvider для быстрого отклика и использование placeholder для первоначального состояния. Также важно поддерживать несколько размеров — пользователь ожидает, что виджет будет доступен как в small, так и в medium варианте. Религиозно избегайте отображения неточных или устаревших данных — пользователь запоминает неправильную информацию с виджета надолго.

Ограничения WidgetKit в таблице

Что нельзяПочему
Анимация и видеоВиджеты — статичные снимки; анимация разряжает батарею
ИнтерактивностьWidgetKit не поддерживает UI-элементы, кроме ссылки на приложение
СкроллингФиксированный размер без прокрутки
КлавиатураВвод текста в виджете невозможен
Живые данныеДанные обновляются по расписанию Timeline, не в реальном времени
Кастомные размерыТолько small, medium, large, accessory* фиксированные

Часто задаваемые вопросы

Можно ли создать один виджет для iOS и macOS?

Да, WidgetKit кроссплатформенный. Один и тот же Widget Extension может быть включён в iOS, iPadOS и macOS таргеты с единым SwiftUI-кодом. Различия проявляются только в поддерживаемых Family — на Mac нет accessoryRectangular.

Как часто WidgetKit обновляет виджеты?

По расписанию Timeline. Разработчик определяет, когда будет следующее обновление — через минуту или через сутки. Система также может ускорять обновления для часто используемых виджетов.

Можно ли добавить кнопку в виджет?

Нет, WidgetKit не поддерживает UIButton или любые интерактивные элементы. Единственное действие — тап по виджету, который открывает приложение deep link.

Как обновить виджет принудительно из приложения?

Используйте WidgetCenter.shared.reloadAllTimelines() или reloadTimelines(ofKind:) для конкретного виджета. Вызов из приложения немедленно запрашивает новый Timeline у провайдера.

Влияют ли виджеты на время работы батареи?

Минимально — менее 1% заряда в день при типичном использовании. WidgetKit ограничивает фоновые обновления и не держит приложение активным. Основной расход — создание Timeline при первом добавлении.

Итоги

  • WidgetKit — фреймворк Apple для виджетов на iOS 14+, iPadOS 14+, macOS 11+ и watchOS 10+, использующий SwiftUI для отображения контента.
  • TimelineProvider управляет расписанием обновлений через массив TimelineEntry, каждая из которых представляет состояние виджета в определённый момент.
  • Widget Family включает три размера — small, medium, large — и accessory-семейства для экрана блокировки iOS 16+.
  • StaticConfiguration подходит для одинакового контента у всех пользователей, IntentConfiguration — для персонализированных виджетов с настройками.
  • Виджеты статичны — без анимации, интерактивности, скроллинга и видео; только read-only отображение данных.
  • Lock Screen виджеты (iOS 16+) представлены accessoryCircular, accessoryRectangular и accessoryInline с ограничениями на контент.
  • Принудительное обновление через WidgetCenter.shared.reloadAllTimelines() позволяет немедленно запросить новый Timeline.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также