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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также