Разработка Live Activities для iOS
Live Activities — функция iOS 16.1+, позволяющая приложению отображать динамический контент прямо на экране блокировки и в Dynamic Island (iPhone 14 Pro+). Такси едет к вам — прогресс-бар на Lock Screen обновляется в реальном времени. Матч идёт — счёт в Dynamic Island без разблокировки телефона.
Живут до 8 часов (или 12 с явным продлением через ActivityKit), потом система сворачивает их. После 12 часов — принудительное завершение.
ActivityKit: архитектура
Live Activity строится на трёх вещах: ActivityAttributes (статические данные, заданные при старте), ContentState (динамические данные, обновляемые через push или API), и SwiftUI View для трёх представлений: Lock Screen / Standby, Dynamic Island Compact, Dynamic Island Expanded.
struct DeliveryAttributes: ActivityAttributes {
// Статика — не меняется во время жизни
let orderId: String
let restaurantName: String
struct ContentState: Codable, Hashable {
// Динамика — обновляется
var status: DeliveryStatus
var estimatedMinutes: Int
var courierLocation: CLLocationCoordinate2D?
}
}
Старт из приложения:
let attributes = DeliveryAttributes(orderId: "1234", restaurantName: "Пицца Юг")
let state = DeliveryAttributes.ContentState(status: .preparing, estimatedMinutes: 30)
let content = ActivityContent(state: state, staleDate: Date().addingTimeInterval(600))
let activity = try Activity.request(
attributes: attributes,
content: content,
pushType: .token // Получить push token для удалённых обновлений
)
staleDate — дата, после которой контент считается устаревшим и система может показать индикатор неактуальности. Для такси: Date() + estimatedMinutes * 60.
Обновление через Push Notifications
Самый надёжный способ обновлять Live Activity с сервера — ActivityKit Push Notifications (не обычные APNs).
Push payload:
{
"aps": {
"timestamp": 1698765432,
"event": "update",
"content-state": {
"status": "in_delivery",
"estimatedMinutes": 12
},
"alert": {
"title": "Курьер выехал",
"body": "Ожидайте через 12 минут"
}
}
}
event: "end" — завершить Live Activity через push. alert в push для Live Activity — отображается как обновление в Dynamic Island с тактильным откликом.
Push token для Live Activity отличается от обычного APNs token. Получаем через activity.pushTokenUpdates AsyncSequence: нужно слушать обновления, потому что token может меняться.
Task {
for await tokenData in activity.pushTokenUpdates {
let token = tokenData.map { String(format: "%02x", $0) }.joined()
await sendTokenToServer(token)
}
}
SwiftUI Views для разных зон
struct DeliveryLiveActivityView: View {
let context: ActivityViewContext<DeliveryAttributes>
var body: some View {
// Lock Screen / StandBy
HStack {
Image(systemName: statusIcon(context.state.status))
VStack(alignment: .leading) {
Text(context.attributes.restaurantName)
.font(.headline)
Text("~\(context.state.estimatedMinutes) мин")
.font(.subheadline)
}
Spacer()
DeliveryProgressView(status: context.state.status)
}
.padding()
}
}
DynamicIsland builder для Dynamic Island:
DynamicIsland {
// Expanded — долгий тап
DynamicIslandExpandedRegion(.leading) {
Image(systemName: "bicycle")
}
DynamicIslandExpandedRegion(.trailing) {
Text("\(context.state.estimatedMinutes) мин")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Курьер: \(courierName)")
}
} compactLeading: {
Image(systemName: "bicycle")
} compactTrailing: {
Text("\(context.state.estimatedMinutes)м")
} minimal: {
Image(systemName: "bicycle")
}
Compact — две зоны по бокам «острова» при свёрнутом состоянии. Minimal — одна маленькая иконка когда есть несколько активных Live Activities.
Ограничения, которые важно знать
Размер ContentState — не более 4KB в ActivityKit push payload. Для координат курьера: не передавать весь трек, только текущую позицию.
Приложение должно быть на переднем плане или иметь Background Push для старта Live Activity. Нельзя стартовать из background без пользовательского действия (с iOS 17.2 — можно через ActivityAuthorizationInfo().areActivitiesEnabled).
Симулятор поддерживает Live Activities с iOS 16.2 Simulator. Dynamic Island — только на физическом устройстве iPhone 14 Pro/Pro Max и новее.
Срок: 3-5 дней для базовой реализации с push-обновлениями. Стоимость зависит от сложности UI и наличия серверной части.







