TipKit
Ajoutez des conseils de découverte de fonctionnalités, des indices contextuels et des marques de coach d'intégration aux applications iOS 17+ à l'aide du framework TipKit d'Apple. TipKit gère la fréquence d'affichage, les règles d'éligibilité et la persistance afin que les conseils apparaissent au bon moment et disparaissent une fois que l'utilisateur a appris la fonctionnalité.
Contenu
- Configuration
- Définition des conseils
- Affichage des conseils
- Règles des conseils
- Actions des conseils
- Groupes de conseils
- Contrôle programmatique
- Erreurs courantes
- Liste de vérification pour la révision
- Références
Configuration
Appelez Tips.configure() une fois dans App.init, avant que les vues ne soient rendues. Cette action initialise le magasin de données des conseils et commence l'évaluation des règles. L'appeler plus tard risque une situation de compétition où les vues de conseils tentent de s'afficher avant que le magasin de données ne soit prêt.
import SwiftUI
import TipKit
@main
struct MyApp: App {
init() {
try? Tips.configure([
.datastoreLocation(.applicationDefault)
])
}
var body: some Scene {
WindowGroup { ContentView() }
}
}
Options DatastoreLocation
| Option | Cas d'utilisation |
|---|---|
.applicationDefault | Emplacement par défaut, bac à sable de l'application (la plupart des applications) |
.groupContainer(identifier:) | Partager l'état des conseils entre l'application et les extensions |
.url(_:) | URL de fichier personnalisée pour un contrôle total de l'emplacement de stockage |
Synchronisation CloudKit
Synchronisez l'état des conseils entre les appareils d'un utilisateur afin qu'il ne voie pas le même conseil sur chaque appareil. Ajoutez l'option de conteneur CloudKit en plus de l'emplacement du magasin de données.
try? Tips.configure([
.datastoreLocation(.applicationDefault),
.cloudKitContainer(.named("iCloud.com.example.app"))
])
Définition des conseils
Conformez une structure au protocole Tip. Fournissez au minimum un title. Ajoutez un message pour les détails d'accompagnement et une image pour une icône principale. Gardez les titres courts et orientés vers l'action car le conseil apparaît sous forme de légende compacte.
import TipKit
struct FavoriteTip: Tip {
var title: Text { Text("Épinglez vos favoris") }
var message: Text? { Text("Appuyez sur l'icône en forme de cœur pour enregistrer les éléments et y accéder rapidement.") }
var image: Image? { Image(systemName: "heart") }
}
Propriétés : title (obligatoire), message (détail optionnel), image (icône principale optionnelle), actions (boutons optionnels), rules (conditions d'éligibilité optionnelles), options (fréquence d'affichage, nombre maximum).
Cycle de vie : En attente (règles non satisfaites) -> Éligible (toutes les règles passent) -> Invalidé (rejeté, actionné ou supprimé par programme). Une fois invalidé, un conseil ne réapparaît pas à moins que le magasin de données ne soit réinitialisé.
Affichage des conseils
Conseils intégrés avec TipView
Intégrez une TipView directement dans votre mise en page. Elle s'affiche sous forme de carte arrondie qui apparaît et disparaît avec une animation. Utilisez-la pour les conseils dans le contenu défilant.
let favoriteTip = FavoriteTip()
var body: some View {
VStack {
TipView(favoriteTip)
ItemListView()
}
}
Conseils contextuels avec .popoverTip()
Attachez un conseil comme une popover ancrée à n'importe quelle vue. Le framework dessine une flèche de la popover vers l'ancre. Utilisez-la pour les conseils pointant vers un contrôle spécifique.
Button { toggleFavorite() } label: { Image(systemName: "heart") }
.popoverTip(favoriteTip)
// Contrôler la direction de la flèche (omettre pour laisser le système choisir)
.popoverTip(favoriteTip, arrowEdge: .bottom)
Style TipView personnalisé
Créez un style personnalisé pour contrôler l'apparence des conseils dans l'application. Conformez-vous à TipViewStyle et implémentez makeBody(configuration:).
struct CustomTipStyle: TipViewStyle {
func makeBody(configuration: Configuration) -> some View {
HStack(spacing: 12) {
configuration.image?
.font(.title2)
.foregroundStyle(.tint)
VStack(alignment: .leading, spacing: 4) {
configuration.title
.font(.headline)
configuration.message?
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
.padding()
}
}
// Appliquer globalement ou par vue
TipView(favoriteTip)
.tipViewStyle(CustomTipStyle())
Règles des conseils
Les règles contrôlent quand un conseil devient éligible. Toutes les règles du tableau rules doivent passer avant que le conseil ne s'affiche. TipKit prend en charge deux types de règles : basées sur les paramètres et basées sur les événements.
Règles basées sur les paramètres
Utilisez @Parameter pour suivre l'état de l'application. Le conseil devient éligible lorsque la valeur du paramètre satisfait la condition de la règle.
struct FavoriteTip: Tip {
@Parameter
static var hasSeenList: Bool = false
var title: Text { Text("Épinglez vos favoris") }
var rules: [Rule] {
#Rule(Self.$hasSeenList) { $0 == true }
}
}
// Définir le paramètre lorsque l'utilisateur atteint la liste
FavoriteTip.hasSeenList = true
Règles basées sur les événements
Utilisez Tips.Event pour suivre les actions de l'utilisateur. Faites un don à l'événement à chaque fois que l'action se produit. La règle se déclenche lorsque le nombre de dons ou la condition de synchronisation est satisfaite. C'est idéal pour les conseils qui doivent apparaître après que l'utilisateur a effectué une action plusieurs fois sans découvrir une fonctionnalité connexe.
struct ShortcutTip: Tip {
static let appOpenedEvent = Tips.Event(id: "appOpened")
var title: Text { Text("Essayez l'action rapide") }
var rules: [Rule] {
#Rule(Self.appOpenedEvent) { $0.donations.count >= 3 }
}
}
// Faites un don à chaque ouverture de l'application
ShortcutTip.appOpenedEvent.donate()
Combinaison de plusieurs règles
Placez plusieurs règles dans le tableau. Toutes doivent passer (ET logique).
struct AdvancedTip: Tip {
@Parameter
static var isLoggedIn: Bool = false
static let featureUsedEvent = Tips.Event(id: "featureUsed")
var title: Text { Text("Débloquez le mode avancé") }
var rules: [Rule] {
#Rule(Self.$isLoggedIn) { $0 == true }
#Rule(Self.featureUsedEvent) { $0.donations.count >= 5 }
}
}
Options de fréquence d'affichage
Contrôlez la fréquence d'apparition des conseils à l'aide de la propriété options.
struct DailyTip: Tip {
var title: Text { Text("Rappel quotidien") }
var options: [TipOption] {
MaxDisplayCount(3) // Afficher au maximum 3 fois au total
IgnoresDisplayFrequency(true) // Ignorer la limite de fréquence globale
}
}
La fréquence d'affichage globale est définie au moment de la configuration :
try? Tips.configure([
.displayFrequency(.daily) // .immediate, .hourly, .daily, .weekly, .monthly
])
Avec .daily, le système affiche au maximum un conseil par jour dans l'ensemble de l'application, sauf si un conseil spécifique définit IgnoresDisplayFrequency(true).
Actions des conseils
Ajoutez des boutons d'action à un conseil pour une interaction directe. Chaque action a un id et un label. Gérez l'action dans le gestionnaire d'actions de la vue du conseil.
struct FeatureTip: Tip {
var title: Text { Text("Essayez le nouvel éditeur") }
var message: Text? { Text("Nous avons ajouté un nouveau mode d'édition puissant.") }
var actions: [Action] {
Action(id: "open-editor", title: "Ouvrir l'éditeur")
Action(id: "learn-more", title: "En savoir plus")
}
}
Gérez les actions dans la vue :
TipView(featureTip) { action in
switch action.id {
case "open-editor":
navigateToEditor()
featureTip.invalidate(reason: .actionPerformed)
case "learn-more":
showHelpSheet = true
default:
break
}
}
Groupes de conseils
Utilisez TipGroup pour coordonner plusieurs conseils dans une seule vue. TipGroup garantit qu'un seul conseil du groupe s'affiche à la fois, évitant la surcharge de conseils. Les conseils s'affichent par ordre de priorité.
struct OnboardingView: View {
let tipGroup = TipGroup(.ordered) {
WelcomeTip()
NavigationTip()
ProfileTip()
}
var body: some View {
VStack {
if let currentTip = tipGroup.currentTip {
TipView(currentTip)
}
Button("Suivant") {
tipGroup.currentTip?.invalidate(reason: .actionPerformed)
}
}
}
}
Options de priorité
| Initialiseur | Comportement |
|---|---|
.ordered | Les conseils s'affichent dans l'ordre dans lequel ils sont listés |
Lorsque le conseil actuel est invalidé, le prochain conseil éligible du groupe devient currentTip.
Contrôle programmatique
Invalidation des conseils
Appelez invalidate(reason:) lorsque l'utilisateur effectue l'action découverte ou lorsque le conseil n'est plus pertinent.
let tip = FavoriteTip()
tip.invalidate(reason: .actionPerformed)
| Raison | Quand l'utiliser |
|---|---|
.actionPerformed | L'utilisateur a effectué l'action que le conseil décrit |
.displayCountExceeded | Le conseil a atteint son nombre d'affichage maximum |
.tipClosed | L'utilisateur a explicitement rejeté le conseil |
Utilitaires de test
TipKit fournit des méthodes statiques pour contrôler la visibilité des conseils pendant le développement et les tests. Protégez-les avec #if DEBUG ou des vérifications ProcessInfo afin qu'elles ne s'exécutent jamais dans les builds de production.
#if DEBUG
// Afficher tous les conseils, quelles que soient les règles (utile pendant le développement)
Tips.showAllTipsForTesting()
// Afficher uniquement des conseils spécifiques
Tips.showTipsForTesting([FavoriteTip.self, ShortcutTip.self])
// Masquer tous les conseils (utile pour les tests UI qui n'impliquent pas de conseils)
Tips.hideAllTipsForTesting()
// Réinitialiser le magasin de données (efface tout l'état des conseils, invalidations et événements)
try? Tips.resetDatastore()
#endif
Utilisation de ProcessInfo pour les schémas de test
if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
Tips.showAllTipsForTesting()
}
Passez --show-all-tips comme argument de lancement dans le schéma Xcode pour les builds de développement.
Erreurs courantes
NE FAITES PAS : Appeler Tips.configure() ailleurs que dans App.init
Appeler Tips.configure() dans un modificateur onAppear ou task d'une vue crée une situation de compétition où les vues de conseils tentent de s'afficher avant que le magasin de données ne soit prêt, provoquant des conseils manquants ou clignotants.
// FAUX
struct ContentView: View {
var body: some View {
Text("Bonjour")
.task { try? Tips.configure() } // Trop tard, les vues sont déjà rendues
}
}
// CORRECT
@main struct MyApp: App {
init() { try? Tips.configure() }
var body: some Scene { WindowGroup { ContentView() } }
}
NE FAITES PAS : Afficher trop de conseils à la fois
L'affichage de plusieurs conseils simultanément submerge les utilisateurs et dilue l'impact de chaque conseil. Les utilisateurs apprennent à les ignorer.
// FAUX : Trois conseils visibles en même temps
VStack {
TipView(tipA)
TipView(tipB)
TipView(tipC)
}
// CORRECT : Utiliser TipGroup pour les séquencer
let group = TipGroup(.ordered) { TipA(); TipB(); TipC() }
if let currentTip = group.currentTip {
TipView(currentTip)
}
NE FAITES PAS : Oublier d'invalider les conseils après que l'utilisateur a effectué l'action
Si un conseil dit "Appuyez sur l'étoile pour ajouter aux favoris" et que l'utilisateur appuie sur l'étoile mais que le conseil reste, cela érode la confiance dans l'interface utilisateur.
// FAUX : Le conseil reste visible après l'action de l'utilisateur
Button("Favori") { toggleFavorite() }
.popoverTip(favoriteTip)
// CORRECT : Invalider sur action
Button("Favori") {
toggleFavorite()
favoriteTip.invalidate(reason: .actionPerformed)
}
.popoverTip(favoriteTip)
NE FAITES PAS : Laisser les conseils de test activés en production
Tips.showAllTipsForTesting() contourne toutes les règles et limites de fréquence. Expédier cela en production signifie que chaque utilisateur voit immédiatement tous les conseils.
// FAUX : Toujours actif
Tips.showAllTipsForTesting()
// CORRECT : Protégé par DEBUG
#if DEBUG
Tips.showAllTipsForTesting()
#endif
NE FAITES PAS : Rendre les titres des conseils trop longs
Les titres longs sont tronqués ou s'enroulent de manière maladroite dans la légende compacte du conseil. Mettez l'action clé dans le titre et le contexte d'accompagnement dans le message.
// FAUX
var title: Text { Text("Vous pouvez appuyer sur le bouton en forme de cœur pour enregistrer cet élément dans votre liste de favoris") }
// CORRECT
var title: Text { Text("Enregistrer dans les favoris") }
var message: Text? { Text("Appuyez sur l'icône en forme de cœur pour conserver les éléments et y accéder rapidement.") }
NE FAITES PAS : Utiliser des conseils pour des informations critiques
Les utilisateurs peuvent rejeter les conseils à tout moment et ils ne réapparaissent pas. Ne placez jamais d'instructions essentielles ou d'informations de sécurité dans un conseil.
// FAUX : Informations critiques dans un conseil pouvant être rejeté
struct DataLossTip: Tip {
var title: Text { Text("Les modifications non enregistrées seront perdues") }
}
// CORRECT : Utiliser une alerte ou un avertissement en ligne pour les informations critiques
// Réservez les conseils pour la découverte de fonctionnalités et la divulgation progressive
Liste de vérification pour la révision
-
Tips.configure()appelé dansApp.init, avant le rendu des vues - Chaque conseil a un titre clair et concis (orienté action, moins de ~40 caractères)
- Conseils invalidés lorsque l'utilisateur effectue l'action découverte
- Règles définies pour que les conseils apparaissent au bon moment (pas immédiatement au premier lancement pour tous les conseils)
-
TipGrouputilisé lorsqu'il existe plusieurs conseils dans une vue - Utilitaires de test (
showAllTipsForTesting,resetDatastore) protégés par#if DEBUG - Synchronisation CloudKit configurée si l'application prend en charge plusieurs appareils
- Fréquence d'affichage définie de manière appropriée (
.dailyou.weeklypour la plupart des applications) - Conseils utilisés uniquement pour la découverte de fonctionnalités, pas pour des informations critiques
-
TipViewStylepersonnalisé appliqué de manière cohérente si le style par défaut ne correspond pas à la conception de l'application - Actions des conseils gérées et conseil invalidé dans le gestionnaire d'actions
- Dons d'événements placés aux points d'action utilisateur corrects
- Assurez-vous que les types Tip personnalisés sont Sendable ; configurez Tips sur @MainActor
Références
- Voir references/tipkit-patterns.md pour les modèles d'implémentation complets incluant les styles personnalisés, les règles basées sur les événements, les groupes de conseils, les stratégies de test, les flux d'intégration et la configuration des aperçus SwiftUI.