Live Activity is a dynamic widget on iPhone Lock Screen and in Dynamic Island, displaying real-time information: delivery status, sports scores, timers and music playback. It is implemented through ActivityKit (Swift, iOS 16.1+) together with WidgetKit. Live Activity updates locally or via push notifications, supports multiple states and is terminated by the system after the event ends. Learn more at ActivityKit Documentation.
Key Takeaways
Live Activity is an extension of WidgetKit that displays dynamic content on the iPhone Lock Screen and in Dynamic Island. Unlike a static widget that updates on a system timer, Live Activity is launched by the app and lives for a limited time — up to 8 hours for an active Activity and up to 4 hours after completion. The user sees up-to-date data without unlocking the device: delivery order status, distance to destination in a taxi, match results or workout progress.
ActivityKit is a framework for working with Live Activities, introduced in iOS 16.1. It provides an API for requesting, updating and ending Activities. An Activity is an object with content and state. Content (ActivityContent) defines static data, while state (ActivityState) defines dynamic data that changes over time. The system itself decides when to render new state — this saves battery and guarantees smooth animations.
Each Live Activity is uniquely identified by an ActivityID and is tied to one process — the app that created it. The system may end the Activity when memory is low or battery charge is insufficient. The developer receives a notification of forced termination via the ActivityKit delegate and can save the last state for restoration.
Live Activity Architecture is built on two frameworks: WidgetKit handles SwiftUI view rendering, ActivityKit handles the Activity lifecycle. The developer creates a WidgetBundle with LiveActivityConfiguration support. Each configuration defines the data type (Attributes and State) and a SwiftUI View that the system renders on Lock Screen and Dynamic Island. Data is passed through ActivityAttributes — a struct with let fields for content and var fields for state.
| Component | Purpose | API |
|---|---|---|
| Attributes | Static data of the entire Activity | let name: String, let icon: String |
| ContentState | Dynamic state, modified on update | var progress: Double, var status: Status |
| Activity | Request and management object for Activity | Activity.request(attributes:content:) |
| PushToken | Token for server push updates | activity.pushToken publisher |
| ActivityUI | SwiftUI View for Lock Screen and Dynamic Island | LockScreenView, ExpandedView, CompactView |
Activity Lifecycle includes three phases: active (system displays and updates), final (activity ended but UI still visible for 4 hours), removed (system removes UI). The app can end the Activity at any time. The system also ends Activities forcibly — for example, on device restart or when the 8-hour limit expires.
import ActivityKit
struct DeliveryAttributes: ActivityAttributes {
public struct ContentState: Codable & Hashable {
var status: DeliveryStatus
var estimatedMinutes: Int
}
var orderNumber: String
var restaurantName: String
}
WidgetBundle registers Live Activity via the @main macro: the widget returns a list of configurations including LiveActivityConfiguration. Based on this configuration, the system knows what data types to expect and how to render UI in different states — compact, minimal and expanded for Dynamic Island.
Creating an Activity starts with a request to ActivityKit. The app calls Activity.request(attributes:content:pushType:) with initial data. The system checks whether Dynamic Island is available on the device and returns an Activity object. The request may fail if the Active Activity limit is exceeded — typically no more than 5 simultaneously. After a successful request, the system displays the widget on Lock Screen and, if available, in 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 for Live Activity uses LockScreenView, ExpandedView and CompactView structures from WidgetKit. The View receives context (ActivityViewContext) with current attributes and state. View updates happen automatically when new state arrives from the system. Live Activity supports only a limited set of SwiftUI components — Text, Image, HStack, VStack and a few modifiers.
Each Live Activity View must be lightweight and fast — the system refuses to render heavy views. The rendering time limit is 30 ms per frame. Animations are limited to system transitions between states — custom animations in Live Activity are not available. Rendering is performed in a background WidgetKit process with Lock Screen responsiveness priority.
Local Update — the app updates Activity state by calling activity.update(using:). The method accepts a new ContentState and an optional AlertConfiguration for showing a notification on update. Local updates are fast — the system redraws the View on the next render cycle, typically within 1–2 seconds. For frequent updates (timer, stopwatch) use local mode — it is more reliable and faster than 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 Updates — the server sends an ActivityKit push notification with the new state in JSON format. For this, the app receives a pushToken from the activity.pushToken publisher and passes it to the server. The server sends a POST request to APNs with a payload containing the new ContentState. The system receives the push, decodes the state and updates the Live Activity without app involvement — this allows updating the Activity even when the app is closed.
Push updates are more efficient than local updates for infrequent updates (delivery status every 5–10 minutes) — the app does not need to maintain a network connection. For frequent updates every 1–2 seconds use the local method. The server payload includes only the mutable fields of ContentState — static Attributes data is sent only when creating the Activity.
Dynamic Island is a hardware-software area on iPhone 14 Pro, 15 Pro and newer that adapts to Live Activity content. The system automatically displays the Activity in three modes: compact (icon + short text to the left of the cutout), minimal (icon only) and expanded (300pt rectangle with information). The developer does not directly control these modes — the system selects the mode based on priority and available space.
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 supports interactivity — the user taps the area and enters the app or opens the expanded view. Tapping compact mode switches to expanded, and swiping left dismisses the Activity to minimal mode. Buttons in expanded mode (pause/cancel) are handled via Link from SwiftUI — the system launches the app with a deep link URL, processing is done in UIApplicationDelegate.
Dynamic Island Limitations: expanded mode width is up to 300pt, compact text is up to 30 characters. Colors and fonts match the system theme — customization is limited. Transition animations between modes are system-defined and cannot be customized. If multiple apps have active Activities, Dynamic Island displays them with priority based on launch time and content type.
Frequently Asked Questions
A regular WidgetKit widget displays static information and updates on a system timer with a minimum interval of 15–30 minutes. Live Activity shows dynamic data in real time on Lock Screen and Dynamic Island. Live Activity is launched by the app, lives up to 8 hours and is terminated by the system after the event ends, unlike a widget that exists permanently.
Live Activity supports two update modes: local — the app updates state via ActivityKit API at any moment, and push update — the server sends an ActivityKit push notification which the system converts into a new widget state. When the battery is low, the system may freeze Live Activity until charging is connected.
Live Activities are available on iPhone with iOS 16.1 and newer. On iPhone 14 Pro and newer, Live Activity also displays in Dynamic Island. On iPad, Live Activity is supported only on Lock Screen — Dynamic Island is not available on iPad. Apple Watch does not support Live Activities directly, but can display completion notifications.
The system limits the number of active Live Activities — typically no more than 5 simultaneously for all apps. Attempting to start beyond the limit returns an error from ActivityKit. Each Live Activity can have multiple states — for example, pending, in transit, delivered for a food order. After completion, the Activity remains in UI for another 4 hours.
Yes, the app must request permission to send notifications — Live Activity uses the system notification channel. The user can disable Live Activity for a specific app in settings. On first launch, ActivityKit shows a dialog requesting permission. Without permission, the Activity request fails.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also