-
Meet ActivityKit
Live Activities are a glanceable way for someone to keep track of the progress of a task within your app. We'll teach you how you can create helpful experiences for the Lock Screen, the Dynamic Island, and StandBy. Learn how to update your app's Live Activities, monitor activity state, and take advantage of WidgetKit and SwiftUI to build richer experiences.
Capítulos
- 0:00 - Intro
- 0:36 - Live Activity overview
- 4:23 - Lifecycle of Live Activities
- 10:43 - Building Live Activity UI
- 16:37 - Wrap-up
Recursos
- Human Interface Guidelines: Live Activities
- Starting and updating Live Activities with ActivityKit push notifications
- Displaying live data with Live Activities
- ActivityKit
- WidgetKit
Vídeos relacionados
WWDC23
-
Buscar neste vídeo...
-
-
5:40 - Define ActivityAttributes
import ActivityKit struct AdventureAttributes: ActivityAttributes { let hero: EmojiRanger struct ContentState: Codable & Hashable { let currentHealthLevel: Double let eventDescription: String } } -
6:28 - Request Live Activity with initial content state
let adventure = AdventureAttributes(hero: hero) let initialState = AdventureAttributes.ContentState( currentHealthLevel: hero.healthLevel, eventDescription: "Adventure has begun!" ) let content = ActivityContent(state: initialState, staleDate: nil, relevanceScore: 0.0) let activity = try Activity.request( attributes: adventure, content: content, pushType: nil ) -
8:00 - Update Live Activity with new content
let heroName = activity.attributes.hero.name let contentState = AdventureAttributes.ContentState( currentHealthLevel: hero.healthLevel, eventDescription: "\(heroName) has taken a critical hit!" ) var alertConfig = AlertConfiguration( title: "\(heroName) has taken a critical hit!", body: "Open the app and use a potion to heal \(heroName)", sound: .default ) activity.update( ActivityContent<AdventureAttributes.ContentState>( state: contentState, staleDate: nil ), alertConfiguration: alertConfig ) -
9:30 - Observe activity state
// Observe activity state asynchronously func observeActivity(activity: Activity<AdventureAttributes>) { Task { for await activityState in activity.activityStateUpdates { if activityState == .dismissed { self.cleanUpDismissedActivity() } } } } // Observe activity state synchronously let activityState = activity.activityState if activityState == .dismissed { self.cleanUpDismissedActivity() } -
10:03 - Dismiss Live Activity with final content state
let hero = activity.attributes.hero let finalContent = AdventureAttributes.ContentState( currentHealthLevel: hero.healthLevel, eventDescription: "Adventure over! \(hero.name) has defeated the boss! Congrats!" ) let dismissalPolicy: ActivityUIDismissalPolicy = .default activity.end( ActivityContent(state: finalContent, staleDate: nil), dismissalPolicy: dismissalPolicy) } -
10:50 - Add ActivityConfiguration to WidgetBundle
import WidgetKit import SwiftUI @main struct EmojiRangersWidgetBundle: WidgetBundle { var body: some Widget { EmojiRangerWidget() LeaderboardWidget() AdventureActivityConfiguration() } } -
11:05 - Define Lock Screen presentation
struct AdventureActivityConfiguration: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: AdventureAttributes.self) { context in AdventureLiveActivityView( hero: context.attributes.hero, isStale: context.isStale, contentState: context.state ) .activityBackgroundTint(Color.navyBlue) } dynamicIsland: { context in // ... } } } -
13:28 - Define Dynamic Island compact presentation
struct AdventureActivityConfiguration: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: AdventureAttributes.self) { context in // ... } dynamicIsland: { context in DynamicIsland { // ... } compactLeading: { Avatar(hero: context.attributes.hero) } compactTrailing: { ProgressView(value: context.state.currentHealthLevel) { Text("\(Int(context.state.currentHealthLevel * 100))") } .progressViewStyle(.circular) .tint(context.state.currentHealthLevel <= 0.2 ? Color.red : Color.green) } minimal: { // ... } } } } -
14:42 - Define Dynamic Island minimal presentation
struct AdventureActivityConfiguration: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: AdventureAttributes.self) { context in // ... } dynamicIsland: { context in DynamicIsland { // ... } compactLeading: { // ... } compactTrailing: { // ... } minimal: { ProgressView(value: context.state.currentHealthLevel) { Avatar(hero: context.attributes.hero) } .progressViewStyle(.circular) .tint(context.state.currentHealthLevel <= 0.2 ? Color.red : Color.green) } } } } -
15:26 - Define Dynamic Island expanded presentation
struct AdventureActivityConfiguration: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: AdventureAttributes.self) { context in // ... } dynamicIsland: { context in DynamicIsland { // Leading region DynamicIslandExpandedRegion(.leading) { LiveActivityAvatarView(hero: hero) } // Expanded region DynamicIslandExpandedRegion(.trailing) { StatsView(hero: hero, isStale: isStale) } // Bottom region DynamicIslandExpandedRegion(.bottom) { HealthBar(currentHealthLevel: contentState.currentHealthLevel) EventDescriptionView(hero: hero, contentState: contentState) } } compactLeading: { // ... } compactTrailing: { // ... } minimal: { // ... } } } }
-