Skip to main content

live-activities

Live Activities: ActivityKit, Dynamic Island, Lock Screen widgets, push updates. Use when implementing app features related to live activities.

Informações da origem

Repositório
moasq/nanowave
Última atividade na origem
20 de março de 2026 às 18:33
Idioma detectado do SKILL.md
inglês
Estrelas
32
Forks
9

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
live-activities
description
Live Activities: ActivityKit, Dynamic Island, Lock Screen widgets, push updates. Use when implementing app features related to live activities.
tags
swiftui, ios, extensions
platforms
ios
# Live Activities LIVE ACTIVITIES (ActivityKit + Dynamic Island): FRAMEWORK: import ActivityKit SETUP: - Requires separate extension target (kind: "live_activity" in plan extensions array) - NSSupportsLiveActivities: YES is auto-configured on the main app target in project.yml - AppGroup entitlements are auto-configured for data sharing between app and extension ATTRIBUTES (define in Shared/ directory so both app and extension compile it): struct DeliveryAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { var status: String // Mutable: changes during the activity var progress: Double } var orderID: String // Static: set at start, cannot change } STARTING AN ACTIVITY (in app): let attributes = DeliveryAttributes(orderID: "123") let initialState = DeliveryAttributes.ContentState(status: "Preparing", progress: 0.0) let content = ActivityContent(state: initialState, staleDate: nil) let activity = try Activity.request(attributes: attributes, content: content) UPDATING AN ACTIVITY: let updatedState = DeliveryAttributes.ContentState(status: "On the way", progress: 0.6) let updatedContent = ActivityContent(state: updatedState, staleDate: nil) await activity.update(updatedContent) ENDING AN ACTIVITY: await activity.end(nil, dismissalPolicy: .immediate) LOCK SCREEN / DYNAMIC ISLAND UI (in extension): struct DeliveryLiveActivityView: View { let context: ActivityViewContext<DeliveryAttributes> var body: some View { HStack { Text(context.state.status); ProgressView(value: context.state.progress) } } } struct DeliveryWidget: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: DeliveryAttributes.self) { context in DeliveryLiveActivityView(context: context) // Lock Screen } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { Text(context.state.status) } DynamicIslandExpandedRegion(.trailing) { ProgressView(value: context.state.progress) } } compactLeading: { Image(systemName: "bicycle") } compactTrailing: { Text("\(Int(context.state.progress * 100))%") } minimal: { ProgressView(value: context.state.progress) } } } } MANDATORY FILES (every live activity extension MUST have ALL of these): 1. {Name}Bundle.swift — @main WidgetBundle entry point. Without this, the extension has no entry point → linker error "undefined symbol: _main" → CodeSign failure. 2. LiveActivityWidget.swift — Widget struct with ActivityConfiguration(for: Attributes.self) for Lock Screen and Dynamic Island UI. 3. (Optional) Intents.swift — AppIntents for interactive buttons (complete, skip, etc.). SHARED TYPES (CRITICAL): - ActivityAttributes struct MUST be defined in Shared/ directory (NOT in main app's Models/). Both the main app and the live activity extension compile Shared/, so the type is visible to both. Defining it only in the main app causes "Cannot find type in scope" in the extension. SWIFT 6 CONCURRENCY: - AppIntent static properties MUST use "static let" (not "static var"). Mutable global state violates Swift 6 concurrency rules. - LiveActivityService (if @MainActor) → all ViewModels calling it must also be @MainActor. PUSH-TO-START: Use APNs with activity-update payload to start activities remotely (advanced, requires server). --- ## Extension Configuration # Live Activities LIVE ACTIVITIES (ActivityKit + Dynamic Island): FRAMEWORK: import ActivityKit SETUP: - Requires separate extension target (kind: "live_activity" in plan extensions array) - NSSupportsLiveActivities: YES is auto-configured on the main app target in project.yml - AppGroup entitlements are auto-configured for data sharing between app and extension ATTRIBUTES (define in Shared/ directory so both app and extension compile it): struct DeliveryAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { var status: String // Mutable: changes during the activity var progress: Double } var orderID: String // Static: set at start, cannot change } STARTING AN ACTIVITY (in app): let attributes = DeliveryAttributes(orderID: "123") let initialState = DeliveryAttributes.ContentState(status: "Preparing", progress: 0.0) let content = ActivityContent(state: initialState, staleDate: nil) let activity = try Activity.request(attributes: attributes, content: content) UPDATING AN ACTIVITY: let updatedState = DeliveryAttributes.ContentState(status: "On the way", progress: 0.6) let updatedContent = ActivityContent(state: updatedState, staleDate: nil) await activity.update(updatedContent) ENDING AN ACTIVITY: await activity.end(nil, dismissalPolicy: .immediate) LOCK SCREEN / DYNAMIC ISLAND UI (in extension): struct DeliveryLiveActivityView: View { let context: ActivityViewContext<DeliveryAttributes> var body: some View { HStack { Text(context.state.status); ProgressView(value: context.state.progress) } } } struct DeliveryWidget: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: DeliveryAttributes.self) { context in DeliveryLiveActivityView(context: context) // Lock Screen } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { Text(context.state.status) } DynamicIslandExpandedRegion(.trailing) { ProgressView(value: context.state.progress) } } compactLeading: { Image(systemName: "bicycle") } compactTrailing: { Text("\(Int(context.state.progress * 100))%") } minimal: { ProgressView(value: context.state.progress) } } } } MANDATORY FILES (every live activity extension MUST have ALL of these): 1. {Name}Bundle.swift — @main WidgetBundle entry point. Without this, the extension has no entry point → linker error "undefined symbol: _main" → CodeSign failure. 2. LiveActivityWidget.swift — Widget struct with ActivityConfiguration(for: Attributes.self) for Lock Screen and Dynamic Island UI. 3. (Optional) Intents.swift — AppIntents for interactive buttons (complete, skip, etc.). SHARED TYPES (CRITICAL): - ActivityAttributes struct MUST be defined in Shared/ directory (NOT in main app's Models/). Both the main app and the live activity extension compile Shared/, so the type is visible to both. Defining it only in the main app causes "Cannot find type in scope" in the extension. SWIFT 6 CONCURRENCY: - AppIntent static properties MUST use "static let" (not "static var"). Mutable global state violates Swift 6 concurrency rules. - LiveActivityService (if @MainActor) → all ViewModels calling it must also be @MainActor. PUSH-TO-START: Use APNs with activity-update payload to start activities remotely (advanced, requires server).
Ver no GitHub