-
Make features discoverable with TipKit
Teach people how to use your app with TipKit! Learn how you can create effective educational moments through tips. We'll share how you can build eligibility rules to reach the ideal audience, control tip frequency, and strategies for testing to ensure successful interactions.
Capítulos
- 0:00 - Intro
- 1:27 - Create a tip
- 5:23 - Eligibility rules
- 9:19 - Display and dismissal
- 12:35 - Test tips
- 13:56 - Wrap-up
Recursos
Vídeos relacionados
WWDC24
-
Buscar neste vídeo...
-
-
1:55 - Create a tip
struct FavoriteBackyardTip: Tip { var title: Text { Text("Save as a Favorite") } var message: Text { Text("Your favorite backyards always appear at the top of the list.") } } -
2:48 - Configure TipsCenter
@main struct BackyardBirdsApp: App { var body: some Scene { WindowGroup { ContentView() } } // ... init() { TipsCenter.shared.configure() } } -
3:18 - Add actions and an asset to a tip
struct FavoriteBackyardTip: Tip { var title: Text { Text("Save as a Favorite").foregroundColor(.indigo) } var message: Text { Text("Your favorite backyards always appear at the top of the list.") } var asset: Image { Image(systemName: "star") } var actions: [Action] { [ Tip.Action( id: "learn-more", title: "Learn More" ) ] } } -
4:53 - Create a popover view
private let favoriteBackyardTip = FavoriteBackyardTip() // ... .toolbar { ToolbarItem { Button { backyard.isFavorite.toggle() } label: { Label("Favorite", systemImage: "star") .symbolVariant( backyard.isFavorite ? .fill : .none ) } .popoverMiniTip(tip: favoriteBackyardTip) } } -
6:38 - Add a parameter based rule
struct FavoriteBackyardTip: Tip { @Parameter static var isLoggedIn: Bool = false // ... var rules: Predicate<RuleInput...> { // User is logged in #Rule(Self.$isLoggedIn) { $0 == true } } } -
7:16 - Add an event based rule
struct FavoriteBackyardTip: Tip { @Parameter static var isLoggedIn: Bool = false static let enteredBackyardDetailView: Event = Event<DetailViewDonation>( id: "entered-backyard-detail-view" ) // ... var rules: Predicate<RuleInput...> { // User is logged in #Rule(Self.$isLoggedIn) { $0 == true } // User has entered any backyard detail view at least 3 times #Rule(Self.enteredBackyardDetailView) { $0.count >= 3 } } } -
7:34 - Donate the event when a view appears
.onAppear { FavoriteBackyardTip.enteredBackyardDetailView.donate() } -
7:59 - Filter event donations in an event based rule
// User has entered any backyard detail view at least 3 times in the past 5 days #Rule(Self.enteredBackyardDetailView) { $0.donations.filter { $0.date > Date.now.addingTimeInterval(-5 * 60 * 60 * 24) } .count >= 3 } -
8:34 - Create a custom donation
// Create the associated type extension BackyardDetailTip { struct DetailViewDonation: DonationValue { let backyardID: Int } } // Donate the unique id of the backyard detail being viewed .onAppear { BackyardFavoriteTip.enteredBackyardDetailView.donate( with: .init(backyardID: backyard.id) ) } struct FavoriteBackyardTip: Tip { // ... var rules: Predicate<RuleInput...> { // Update the rule to specify a backyardID #Rule(Self.enteredBackyardDetailView) { $0.donations.filter { $0.date > Date.now.addingTimeInterval(-5 * 60 * 60 * 24) } .largestSubset(by: \.backyardID) .count >= 3 } } } -
9:57 - Configure display frequency
// One tip per day. TipsCenter.shared.configure { DisplayFrequency(.daily) } // One tip per hour. TipsCenter.shared.configure { DisplayFrequency(.hourly) } // Custom configuration. Only show one tip every five days. let fiveDays: TimeInterval = 5 * 24 * 60 * 60 TipsCenter.shared.configure { DisplayFrequency(fiveDays) } // No frequency control. Show all tips as soon as eligible. TipsCenter.shared.configure { DisplayFrequency(.immediate) } -
10:34 - Turn off display frequency controls for a tip
struct FavoriteBackyardTip: Tip { // ... var options: [Option] { [.ignoresDisplayFrequency(true)] } } -
11:27 - Invalidate a tip
Button { backyard.isFavorite.toggle() // When user taps the favorite button, dismiss the tip favoriteBackyardTip.invalidate(reason: .userPerformedAction) } label: { Label("Favorite", systemImage: "star") .symbolVariant(backyard.isFavorite ? .fill : .none) } .popoverMiniTip(tip: favoriteBackyardTip) -
11:41 - Configure max display count on a tip
struct FavoriteBackyardTip: Tip { // ... var options: [Option] { [.maxDisplayCount(5)] } } -
12:46 - Programmatically call testing API
// Show all defined tips in the app TipsCenter.showAllTips() // Show some tips, but not all TipsCenter.showTips([tip1, tip2, tip3]) // Hide some tips, but not all TipsCenter.hideTips([tip1, tip2, tip3]) // Hide all tips defined in the app TipsCenter.hideAllTips() // Purge all TipKit related data TipsCenter.resetDatastore() -
13:31 - Configure launch arguments in your scheme
// Show all defined tips in the app com.apple.TipKit.ShowAllTips 1 // Show some tips, but not all com.apple.TipKit.ShowTips tipID,otherTipID // Hide some tips, but not all com.apple.TipKit.HideAllTips 1 // Hide all tips defined in the app com.apple.TipKit.HideTips tipID,otherTipID // Purge all TipKit related data com.apple.TipKit.ResetDatastore 1
-