Live Activity — динамічний віджет на екрані блокування iPhone та в Dynamic Island, що відображає інформацію в реальному часі: статус доставки, спортивні рахунки, таймери та відтворення музики. Реалізується через ActivityKit (Swift, iOS 16.1+) разом із WidgetKit. Live Activity оновлюється локально або через push-сповіщення, підтримує кілька станів і завершується системою після закінчення події. Детальніше — на ActivityKit Documentation.
Головне
Live Activity — розширення WidgetKit, що відображає динамічний контент на екрані блокування iPhone та в Dynamic Island. На відміну від статичного віджета, який оновлюється за таймером системи, Live Activity запускається додатком і живе обмежений час — до 8 годин для активної Activity та до 4 годин після завершення. Користувач бачить актуальні дані без розблокування пристрою: статус замовлення доставки, відстань до пункту призначення в таксі, результати матчу або прогрес тренування.
ActivityKit — фреймворк для роботи з Live Activities, представлений в iOS 16.1. Він надає API для запиту, оновлення та завершення Activity. Activity — це об'єкт із контентом та станом. Контент (ActivityContent) визначає статичні дані, а стан (ActivityState) — динамічні, що змінюються з часом. Система сама вирішує, коли рендерити новий стан — це економить батарею та гарантує плавність анімацій.
Кожна Live Activity унікально ідентифікується ActivityID і прив'язана до одного процесу — додатка, який її створив. Система може завершити Activity при нестачі пам'яті або низькому заряді батареї. Розробник отримує сповіщення про примусове завершення через делегат ActivityKit і може зберегти останній стан для відновлення.
Архітектура Live Activity будується на двох фреймворках: WidgetKit відповідає за рендеринг SwiftUI-в'ю, ActivityKit — за життєвий цикл Activity. Розробник створює WidgetBundle з підтримкою LiveActivityConfiguration. Кожна конфігурація визначає тип даних (Attributes та State) і SwiftUI View, яка рендериться системою на Lock Screen та Dynamic Island. Дані передаються через ActivityAttributes — struct з let-полями для контенту та var-полями для стану.
| Компонент | Призначення | API |
|---|---|---|
| Attributes | Статичні дані всієї Activity | let name: String, let icon: String |
| ContentState | Динамічний стан, що змінюється при оновленні | var progress: Double, var status: Status |
| Activity | Об'єкт запиту та керування Activity | Activity.request(attributes:content:) |
| PushToken | Токен для серверних push-оновлень | activity.pushToken publisher |
| ActivityUI | SwiftUI View для Lock Screen та Dynamic Island | LockScreenView, ExpandedView, CompactView |
Життєвий цикл Activity включає три фази: активна (система відображає та оновлює), фінальна (активність завершена, але UI ще видимий 4 години), видалена (система прибирає UI). Додаток може завершити Activity в будь-який момент. Система також завершує Activity примусово — наприклад, при перезавантаженні пристрою або закінченні 8-годинного ліміту.
import ActivityKit
struct DeliveryAttributes: ActivityAttributes {
public struct ContentState: Codable & Hashable {
var status: DeliveryStatus
var estimatedMinutes: Int
}
var orderNumber: String
var restaurantName: String
}
WidgetBundle реєструє Live Activity через макрос @main: віджет повертає список конфігурацій, включаючи LiveActivityConfiguration. Система на основі цієї конфігурації знає, які типи даних очікувати та як рендерити UI в різних станах — компактному, мінімальному та розширеному для Dynamic Island.
Створення Activity починається з запиту до ActivityKit. Додаток викликає Activity.request(attributes:content:pushType:) з початковими даними. Система перевіряє, чи доступний Dynamic Island на пристрої, і повертає об'єкт Activity. Запит може завершитися помилкою, якщо перевищено ліміт активних Activity — зазвичай не більше 5 одночасно. Після успішного запиту система відображає віджет на Lock Screen та, якщо можливо, в Dynamic Island.
let attributes = DeliveryAttributes(
orderNumber: "A-1234",
restaurantName: "Pizza House"
)
let initialState = DeliveryAttributes.ContentState(
status: DeliveryStatus.preparing,
estimatedMinutes: 30
)
do {
let activity = try await Activity<DeliveryAttributes>.request(
attributes: attributes,
content: ActivityContent(state: initialState, staleDate: nil),
pushType: .token
)
print("Activity started: \(activity.id)")
} catch {
print("Failed: \(error)")
}
SwiftUI View для Live Activity використовує структури LockScreenView, ExpandedView та CompactView з WidgetKit. View отримує контекст (ActivityViewContext) з поточними атрибутами та станом. Оновлення View відбувається автоматично при отриманні нового стану від системи. Live Activity підтримує лише обмежений набір компонентів SwiftUI — Text, Image, HStack, VStack та кілька модифікаторів.
Кожна Live Activity View має бути легкою та швидкою — система відмовляється рендерити важкі в'ю. Обмеження за часом рендерингу — 30 мс на фрейм. Анімації обмежені системними переходами між станами — кастомні анімації в Live Activity недоступні. Рендеринг виконується в фоновому процесі WidgetKit з пріоритетом чуйності Lock Screen.
Локальне оновлення — додаток оновлює стан Activity викликом activity.update(using:). Метод приймає новий ContentState та опціональний AlertConfiguration для відображення сповіщення при оновленні. Локальні оновлення швидкі — система перемальовує View на наступному циклі рендерингу, зазвичай протягом 1–2 секунд. Для частих оновлень (таймер, секундомір) використовуйте локальний режим — це надійніше та швидше push.
let updatedState = DeliveryAttributes.ContentState(
status: DeliveryStatus.outForDelivery,
estimatedMinutes: 10
)
await activity.update(
ActivityContent<DeliveryAttributes.ContentState>(
state: updatedState,
staleDate: Date().addingTimeInterval(60)
),
alertConfiguration: AlertConfiguration(
title: "Order out for delivery",
body: "Arriving in 10 min"
)
)
Push-оновлення — сервер надсилає ActivityKit push-сповіщення з новим станом у форматі JSON. Для цього додаток отримує pushToken з activity.pushToken publisher і передає його на сервер. Сервер надсилає POST-запит на APNs з payload, що містить новий ContentState. Система отримує push, декодує стан та оновлює Live Activity без участі додатка — це дозволяє оновлювати Activity навіть коли додаток закрито.
Push-оновлення економніші за локальні для рідкісних оновлень (статус доставки кожні 5–10 хвилин) — додатку не потрібно тримати мережеве з'єднання. Для частих оновлень кожні 1–2 секунди використовуйте локальний метод. Серверний payload включає лише змінювані поля ContentState — статичні дані Attributes надсилаються тільки при створенні Activity.
Dynamic Island — апаратно-програмна область на iPhone 14 Pro, 15 Pro та новіших, яка адаптується під контент Live Activity. Система автоматично відображає Activity в трьох режимах: компактний (іконка + короткий текст зліва від вирізу), мінімальний (тільки іконка) та розширений (прямокутник 300pt з інформацією). Розробник не керує цими режимами безпосередньо — система вибирає режим на основі пріоритету та доступного простору.
struct DeliveryLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: DeliveryAttributes.self) { context in
LockScreenView(context: context)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedContent {
ExpandedView(context: context)
}
} compactLeading: {
CompactLeadingView(context: context)
} compactTrailing: {
CompactTrailingView(context: context)
} minimal: {
MinimalView(context: context)
}
}
}
}
Dynamic Island підтримує **інтерактивність** — користувач торкається області та потрапляє в додаток або відкриває розширений вигляд. Натискання на компактний режим переводить у розширений, а свайп вліво прибирає Activity в мінімальний. Кнопки в розширеному режимі (pause/cancel) обробляються через Link з SwiftUI — система запускає додаток з deep link URL, обробка виконується в UIApplicationDelegate.
Обмеження Dynamic Island: ширина розширеного режиму — до 300pt, компактний текст — до 30 символів. Кольори та шрифти відповідають системній темі — кастомізація обмежена. Анімації переходів між режимами системні та не налаштовуються. Якщо кілька додатків мають активні Activity, Dynamic Island показує їх з пріоритетом за часом запуску та типом контенту.
Часті запитання
Звичайний віджет WidgetKit відображає статичну інформацію та оновлюється за таймером системи з мінімальним інтервалом 15–30 хвилин. Live Activity показує динамічні дані в реальному часі на екрані блокування та Dynamic Island. Live Activity запускається додатком, живе до 8 годин та завершується системою після закінчення події, на відміну від віджета, який існує постійно.
Live Activity підтримує два режими оновлення: локальне — додаток оновлює стан через ActivityKit API в будь-який момент, і push-оновлення — сервер надсилає push-сповіщення ActivityKit push, яке система перетворює на новий стан віджета. При низькому заряді батареї система може заморозити Live Activity до підключення зарядки.
Live Activities доступні на iPhone з iOS 16.1 та новіше. На iPhone 14 Pro та новіше Live Activity відображається також в Dynamic Island. На iPad Live Activity підтримується тільки на екрані блокування — Dynamic Island на iPad відсутній. Apple Watch не підтримують Live Activities безпосередньо, але можуть відображати сповіщення про завершення.
Система обмежує кількість активних Live Activities — зазвичай не більше 5 одночасно для всіх додатків. При спробі запустити понад ліміт ActivityKit повертає помилку. Кожна Live Activity може мати кілька станів — наприклад, очікування, в дорозі, доставлено для замовлення їжі. Після завершення Activity залишається в UI ще 4 години.
Так, додаток має запитати дозвіл на надсилання сповіщень — Live Activity використовує системний канал сповіщень. Користувач може вимкнути Live Activity для конкретного додатка в налаштуваннях. При першому запуску ActivityKit показує діалог із запитом дозволу. Без дозволу запит Activity завершується помилкою.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.