Communitygithub.com

TipKit – Feature Discovery & Onboarding für iOS 17+

Implementiere, überprüfe oder verbessere In-App-Tipps und Onboarding mit Apple's TipKit-Framework. Verwende dies für Feature-Entdeckungs-Tooltips, Onboarding-Abläufe, kontextbezogene Tipps, Ersteinführungserlebnisse, Coach Marks oder die Arbeit mit dem Tip-Protokoll, TipView, popoverTip, Tip-Regeln, Tip-Ereignissen oder Feature-Education-UI.

Was ist TipKit – Feature Discovery & Onboarding für iOS 17+?

Dieses Skill beschreibt die Integration von Apple's TipKit-Framework in iOS 17+ Apps, um Feature-Entdeckungs-Tipps und Onboarding-Coach-Marks hinzuzufügen. TipKit verwaltet die Anzeigehäufigkeit, Berechtigungsregeln und Persistenz – Tipps erscheinen im richtigen Moment und verschwinden, sobald der Benutzer die Funktion gelernt hat. Das Skill behandelt die Einrichtung (Tips.configure() im App.init), die Definition von Tipps (Tip-Protokoll mit title, message, image, actions, rules, options) und die Darstellung (inline mit TipView, als Popover mit .popoverTip() oder benutzerdefiniert mit TipViewStyle). Es erklärt detailliert die Regeltypen (parameterbasiert über @Parameter und ereignisbasiert über Tips.Event), die Kombination mehrerer Regeln (logisches UND), die Steuerung der Anzeigehäufigkeit (global und pro Tipp mit MaxDisplayCount, IgnoresDisplayFrequency) sowie Tip-Gruppen (TipGroup) um Tip-Überlastung zu vermeiden. Darüber hinaus werden Aktionen (Tip-Actions), programmatische Steuerung (Invalidierung, Test-Tools wie showAllTipsForTesting und resetDatastore) sowie häufige Fehler (falscher Aufruf von configure, zu viele Tipps, fehlende Invalidierung, zu lange Titel, kritische Informationen in Tipps) und eine umfassende Review-Checkliste behandelt. Das Skill ist sowohl für Entwickler als auch für KI-Agenten gedacht, die TipKit in SwiftUI-Projekten implementieren oder bestehende Implementierungen überprüfen möchten.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/JordanCoin/ios-skills-collection/tree/HEAD/skills/dpearson2699--tipkit

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

TipKit

Füge Feature-Entdeckungstipps, kontextbezogene Hinweise und Onboarding-Coach-Marks zu iOS 17+ Apps hinzu, indem du Apple's TipKit-Framework verwendest. TipKit verwaltet die Anzeigehäufigkeit, Berechtigungsregeln und Persistenz, sodass Tipps im richtigen Moment erscheinen und verschwinden, sobald der Benutzer die Funktion gelernt hat.

Inhalt

Einrichtung

Rufe Tips.configure() einmal in App.init auf, bevor irgendeine Ansicht gerendert wird. Dadurch wird der Tipp-Datenspeicher initialisiert und die Regelauswertung beginnt. Ein späterer Aufruf riskiert eine Race-Bedingung, bei der Tipp-Ansichten versuchen anzuzeigen, bevor der Datenspeicher bereit ist.

import SwiftUI
import TipKit

@main
struct MyApp: App {
    init() {
        try? Tips.configure([
            .datastoreLocation(.applicationDefault)
        ])
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Datenspeicher-Optionen

OptionAnwendungsfall
.applicationDefaultStandardort, App-Sandbox (die meisten Apps)
.groupContainer(identifier:) Tipp-Status zwischen App und Erweiterungen teilen
.url(_:)Benutzerdefinierte Datei-URL für volle Kontrolle über den Speicherort

CloudKit-Synchronisation

Synchronisiere den Tipp-Status über die Geräte eines Benutzers, damit er denselben Tipp nicht auf jedem Gerät sieht. Füge die CloudKit-Container-Option zusammen mit dem Datenspeicherort hinzu.

try? Tips.configure([
    .datastoreLocation(.applicationDefault),
    .cloudKitContainer(.named("iCloud.com.example.app"))
])

Tipps definieren

Erstelle eine Struktur, die dem Tip-Protokoll entspricht. Gib mindestens einen title an. Füge message für unterstützende Details und image für ein führendes Symbol hinzu. Halte Titel kurz und handlungsorientiert, da der Tipp als kompakte Sprechblase erscheint.

import TipKit

struct FavoriteTip: Tip {
    var title: Text { Text("Favoriten anheften") }
    var message: Text? { Text("Tippe auf das Herz-Symbol, um Elemente für schnellen Zugriff zu speichern.") }
    var image: Image? { Image(systemName: "heart") }
}

Eigenschaften: title (erforderlich), message (optionales Detail), image (optionales führendes Symbol), actions (optionale Buttons), rules (optionale Berechtigungsbedingungen), options (Anzeigehäufigkeit, maximale Anzahl).

Lebenszyklus: Ausstehend (Regeln nicht erfüllt) -> Berechtigt (alle Regeln erfüllt) -> Ungültig (geschlossen, bearbeitet oder programmatisch entfernt). Ein einmal ungültig gemachter Tipp erscheint nicht wieder, es sei denn, der Datenspeicher wird zurückgesetzt.

Tipps anzeigen

Inline-Tipps mit TipView

Bette eine TipView direkt in dein Layout ein. Sie wird als abgerundete Karte dargestellt, die mit Animation erscheint und verschwindet. Verwende sie für Tipps in scrollbaren Inhalten.

let favoriteTip = FavoriteTip()
var body: some View {
    VStack {
        TipView(favoriteTip)
        ItemListView()
    }
}

Popover-Tipps mit .popoverTip()

Binde einen Tipp als Popover an eine beliebige Ansicht. Das Framework zeichnet einen Pfeil vom Popover zum Anker. Verwende dies für Tipps, die auf ein bestimmtes Steuerelement zeigen.

Button { toggleFavorite() } label: { Image(systemName: "heart") }
    .popoverTip(favoriteTip)

// Pfeilrichtung steuern (weglassen, damit das System wählt)
.popoverTip(favoriteTip, arrowEdge: .bottom)

Benutzerdefinierter TipViewStyle

Erstelle einen benutzerdefinierten Stil, um das Erscheinungsbild von Tipps in der gesamten App zu steuern. Implementiere das TipViewStyle-Protokoll und dessen makeBody(configuration:)-Methode.

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()
    }
}

// Global oder pro Ansicht anwenden
TipView(favoriteTip)
    .tipViewStyle(CustomTipStyle())

Tipp-Regeln

Regeln steuern, wann ein Tipp berechtigt wird. Alle Regeln im rules-Array müssen erfüllt sein, bevor der Tipp angezeigt wird. TipKit unterstützt zwei Regeltypen: parameterbasierte und ereignisbasierte.

Parameterbasierte Regeln

Verwende @Parameter, um den App-Status zu verfolgen. Der Tipp wird berechtigt, wenn der Parameterwert die Regelbedingung erfüllt.

struct FavoriteTip: Tip {
    @Parameter
    static var hasSeenList: Bool = false

    var title: Text { Text("Favoriten anheften") }

    var rules: [Rule] {
        #Rule(Self.$hasSeenList) { $0 == true }
    }
}

// Setze den Parameter, wenn der Benutzer die Liste erreicht
FavoriteTip.hasSeenList = true

Ereignisbasierte Regeln

Verwende Tips.Event, um Benutzeraktionen zu verfolgen. Spende jedes Mal an das Ereignis, wenn die Aktion ausgeführt wird. Die Regel feuert, wenn die Spendenanzahl oder der Zeitpunkt erfüllt ist. Dies ist ideal für Tipps, die erscheinen sollen, nachdem der Benutzer eine Aktion mehrmals ausgeführt hat, ohne eine verwandte Funktion entdeckt zu haben.

struct ShortcutTip: Tip {
    static let appOpenedEvent = Tips.Event(id: "appOpened")

    var title: Text { Text("Probiere die Schnellaktion") }

    var rules: [Rule] {
        #Rule(Self.appOpenedEvent) { $0.donations.count >= 3 }
    }
}

// Spende jedes Mal, wenn die App geöffnet wird
ShortcutTip.appOpenedEvent.donate()

Mehrere Regeln kombinieren

Füge mehrere Regeln in das Array ein. Alle müssen erfüllt sein (logisches UND).

struct AdvancedTip: Tip {
    @Parameter
    static var isLoggedIn: Bool = false

    static let featureUsedEvent = Tips.Event(id: "featureUsed")

    var title: Text { Text("Erweiterten Modus freischalten") }

    var rules: [Rule] {
        #Rule(Self.$isLoggedIn) { $0 == true }
        #Rule(Self.featureUsedEvent) { $0.donations.count >= 5 }
    }
}

Anzeigehäufigkeitsoptionen

Steuere, wie oft Tipps erscheinen, mit der options-Eigenschaft.

struct DailyTip: Tip {
    var title: Text { Text("Tägliche Erinnerung") }

    var options: [TipOption] {
        MaxDisplayCount(3)                   // Maximal 3 Mal insgesamt anzeigen
        IgnoresDisplayFrequency(true)        // Globale Häufigkeitsbegrenzung umgehen
    }
}

Die globale Anzeigehäufigkeit wird bei der Konfiguration festgelegt:

try? Tips.configure([
    .displayFrequency(.daily)  // .immediate, .hourly, .daily, .weekly, .monthly
])

Mit .daily zeigt das System höchstens einen Tipp pro Tag in der gesamten App an, es sei denn, ein bestimmter Tipp setzt IgnoresDisplayFrequency(true).

Tipp-Aktionen

Füge Aktions-Buttons zu einem Tipp hinzu, um direkte Interaktion zu ermöglichen. Jede Aktion hat eine id und ein Label. Behandle die Aktion im Action-Handler der Tippansicht.

struct FeatureTip: Tip {
    var title: Text { Text("Probiere den neuen Editor") }
    var message: Text? { Text("Wir haben einen leistungsstarken neuen Bearbeitungsmodus hinzugefügt.") }

    var actions: [Action] {
        Action(id: "open-editor", title: "Editor öffnen")
        Action(id: "learn-more", title: "Mehr erfahren")
    }
}

Aktionen in der Ansicht behandeln:

TipView(featureTip) { action in
    switch action.id {
    case "open-editor":
        navigateToEditor()
        featureTip.invalidate(reason: .actionPerformed)
    case "learn-more":
        showHelpSheet = true
    default:
        break
    }
}

Tipp-Gruppen

Verwende TipGroup, um mehrere Tipps innerhalb einer einzelnen Ansicht zu koordinieren. TipGroup stellt sicher, dass immer nur ein Tipp aus der Gruppe gleichzeitig angezeigt wird, um Tipp-Überlastung zu vermeiden. Tipps werden in priorisierter Reihenfolge angezeigt.

struct OnboardingView: View {
    let tipGroup = TipGroup(.ordered) {
        WelcomeTip()
        NavigationTip()
        ProfileTip()
    }

    var body: some View {
        VStack {
            if let currentTip = tipGroup.currentTip {
                TipView(currentTip)
            }

            Button("Weiter") {
                tipGroup.currentTip?.invalidate(reason: .actionPerformed)
            }
        }
    }
}

Prioritätsoptionen

InitialisiererVerhalten
.orderedTipps werden in der Reihenfolge angezeigt, in der sie aufgelistet sind

Wenn der aktuelle Tipp ungültig gemacht wird, wird der nächste berechtigte Tipp in der Gruppe zum currentTip.

Programmatische Steuerung

Tipps ungültig machen

Rufe invalidate(reason:) auf, wenn der Benutzer die entdeckte Aktion ausführt oder der Tipp nicht mehr relevant ist.

let tip = FavoriteTip()
tip.invalidate(reason: .actionPerformed)
GrundWann verwenden
.actionPerformedBenutzer hat die im Tipp beschriebene Aktion ausgeführt
.displayCountExceededTipp hat seine maximale Anzeigeanzahl erreicht
.tipClosedBenutzer hat den Tipp explizit geschlossen

Test-Hilfsmittel

TipKit bietet statische Methoden, um die Tippsichtbarkeit während der Entwicklung und des Testens zu steuern. Schütze diese mit #if DEBUG oder ProcessInfo-Prüfungen, damit sie nie in Produktions-Builds ausgeführt werden.

#if DEBUG
// Alle Tipps anzeigen, unabhängig von Regeln (nützlich während der Entwicklung)
Tips.showAllTipsForTesting()

// Nur bestimmte Tipps anzeigen
Tips.showTipsForTesting([FavoriteTip.self, ShortcutTip.self])

// Alle Tipps ausblenden (nützlich für UI-Tests, die keine Tipps betreffen)
Tips.hideAllTipsForTesting()

// Datenspeicher zurücksetzen (löscht alle Tipp-Status, Ungültigmachungen und Ereignisse)
try? Tips.resetDatastore()
#endif

Verwenden von ProcessInfo für Testschemata

if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
    Tips.showAllTipsForTesting()
}

Füge --show-all-tips als Startargument im Xcode-Schema für Entwicklungs-Builds hinzu.

Häufige Fehler

NICHT: Tips.configure() an einer anderen Stelle als App.init aufrufen

Ein Aufruf von Tips.configure() in einem onAppear- oder task-Modifier einer Ansicht erzeugt eine Race-Bedingung, bei der Tipp-Ansichten versuchen zu rendern, bevor der Datenspeicher bereit ist, was zu fehlenden oder flackernden Tipps führt.

// FALSCH
struct ContentView: View {
    var body: some View {
        Text("Hallo")
            .task { try? Tips.configure() }  // Zu spät, Ansichten wurden bereits gerendert
    }
}

// RICHTIG
@main struct MyApp: App {
    init() { try? Tips.configure() }
    var body: some Scene { WindowGroup { ContentView() } }
}

NICHT: Zu viele Tipps auf einmal anzeigen

Das gleichzeitige Anzeigen mehrerer Tipps überfordert Benutzer und verwässert die Wirkung jedes einzelnen Tipps. Benutzer lernen, sie zu ignorieren.

// FALSCH: Drei Tipps gleichzeitig sichtbar
VStack {
    TipView(tipA)
    TipView(tipB)
    TipView(tipC)
}

// RICHTIG: Verwende TipGroup, um sie zu sequenzieren
let group = TipGroup(.ordered) { TipA(); TipB(); TipC() }
if let currentTip = group.currentTip {
    TipView(currentTip)
}

NICHT: Vergessen, Tipps ungültig zu machen, nachdem der Benutzer die Aktion ausgeführt hat

Wenn ein Tipp sagt "Tippe auf den Stern, um zu favorisieren" und der Benutzer tippt auf den Stern, aber der Tipp bleibt, untergräbt dies das Vertrauen in die UI.

// FALSCH: Tipp bleibt sichtbar, nachdem der Benutzer gehandelt hat
Button("Favorisieren") { toggleFavorite() }
    .popoverTip(favoriteTip)

// RICHTIG: Bei Aktion ungültig machen
Button("Favorisieren") {
    toggleFavorite()
    favoriteTip.invalidate(reason: .actionPerformed)
}
.popoverTip(favoriteTip)

NICHT: Test-Tipps in der Produktion aktiviert lassen

Tips.showAllTipsForTesting() umgeht alle Regeln und Häufigkeitsbegrenzungen. Wenn dies in der Produktion ausgeliefert wird, sieht jeder Benutzer sofort jeden Tipp.

// FALSCH: Immer aktiv
Tips.showAllTipsForTesting()

// RICHTIG: Hinter DEBUG geschützt
#if DEBUG
Tips.showAllTipsForTesting()
#endif

NICHT: Tipp-Titel zu lang machen

Lange Titel werden in der kompakten Tipp-Sprechblase abgeschnitten oder umgebrochen. Setze die Hauptaktion in den Titel und den unterstützenden Kontext in die Nachricht.

// FALSCH
var title: Text { Text("Du kannst auf den Herz-Button tippen, um dieses Element zu deiner Favoritenliste hinzuzufügen") }

// RICHTIG
var title: Text { Text("Zu Favoriten speichern") }
var message: Text? { Text("Tippe auf das Herz-Symbol, um Elemente für schnellen Zugriff zu behalten.") }

NICHT: Tipps für kritische Informationen verwenden

Benutzer können Tipps jederzeit schließen und sie erscheinen nicht wieder. Gib niemals wichtige Anweisungen oder Sicherheitsinformationen in einem Tipp.

// FALSCH: Kritische Info in einem schließbaren Tipp
struct DataLossTip: Tip {
    var title: Text { Text("Ungespeicherte Änderungen gehen verloren") }
}

// RICHTIG: Verwende einen Alert oder Inline-Warnhinweis für kritische Informationen
// Hebe Tipps für Feature-Entdeckung und progressive Offenlegung auf

Review-Checkliste

  • Tips.configure() in App.init aufgerufen, bevor Ansichten gerendert werden
  • Jeder Tipp hat einen klaren, prägnanten Titel (handlungsorientiert, unter ~40 Zeichen)
  • Tipps ungültig gemacht, wenn der Benutzer die entdeckte Aktion ausführt
  • Regeln so gesetzt, dass Tipps zum richtigen Zeitpunkt erscheinen (nicht sofort beim ersten Start für alle Tipps)
  • TipGroup verwendet, wenn mehrere Tipps in einer Ansicht existieren
  • Test-Hilfsmittel (showAllTipsForTesting, resetDatastore) hinter #if DEBUG geschützt
  • CloudKit-Synchronisation konfiguriert, wenn die App mehrere Geräte unterstützt
  • Anzeigehäufigkeit angemessen eingestellt (.daily oder .weekly für die meisten Apps)
  • Tipps nur für Feature-Entdeckung verwendet, nicht für kritische Informationen
  • Benutzerdefinierter TipViewStyle einheitlich angewendet, wenn der Standardstil nicht zum App-Design passt
  • Tipp-Aktionen behandelt und Tipp im Action-Handler ungültig gemacht
  • Ereignisspenden an den richtigen Benutzeraktionspunkten platziert
  • Sicherstellen, dass benutzerdefinierte Tip-Typen Sendable sind; Tips auf @MainActor konfigurieren

Referenzen

  • Siehe references/tipkit-patterns.md für vollständige Implementierungsmuster einschließlich benutzerdefinierter Stile, ereignisbasierter Regeln, Tipp-Gruppen, Teststrategien, Onboarding-Abläufe und SwiftUI-Vorschaukonfiguration.

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

JordanCoin/ios-skills-collection

Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries. Use when the user asks about GitHub issues, pull requests, workflows, or wants to interact with GitHub repositories from the command line — including tasks like check CI status, create PR, list issues, or query the GitHub API.

JordanCoin/ios-skills-collection

Create media playback experiences using AVKit. Use when adding video players with AVPlayerViewController, enabling Picture-in-Picture, routing media with AirPlay, using SwiftUI VideoPlayer views, configuring transport controls, displaying subtitles and closed captions, or integrating AVFoundation playback with system UI.

JordanCoin/ios-skills-collection

Integrate and optimize Core ML models in iOS apps for on-device machine learning inference. Covers model loading (.mlmodelc, .mlpackage), predictions with auto-generated classes and MLFeatureProvider, compute unit configuration (CPU, GPU, Neural Engine), MLTensor, VNCoreMLRequest, MLComputePlan, multi-model pipelines, and deployment strategies. Use when loading Core ML models, making predictions, configuring compute units, or profiling model performance.

JordanCoin/ios-skills-collection

Implement, review, or improve maps and location features in iOS/macOS apps using MapKit and CoreLocation. Use when working with Map views, annotations, markers, polylines, user location tracking, geocoding, reverse geocoding, search/autocomplete, directions and routes, geofencing, region monitoring, CLLocationUpdate async streams, or location authorization flows. Also use when working with maps, coordinates, addresses, places, directions, distance calculations, or location-based features in Swift apps.

JordanCoin/ios-skills-collection

Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signatures), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI.

JordanCoin/ios-skills-collection

When the user wants to optimize their Google Play Store listing — title, short description, full description, keywords, ratings, or Play Store-specific features. Use when the user mentions "Google Play", "Android", "Play Store", "Play Console", "short description", "full description indexed", "Google Play ASO", or wants Google Play-specific keyword, creative, or ratings strategy. For iOS App Store optimization, see aso-audit and metadata-optimization.

JordanCoin/ios-skills-collection

When the user wants to implement, optimize, or use App Clips for app discovery and conversion. Use when the user mentions "App Clip", "app clip code", "mini app", "instant app", "App Clip card", "App Clip link", "no download required", "instant experience", or wants to understand how App Clips appear in App Store search. For general App Store discoverability, see aso-audit. For marketing campaigns, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to plan a launch strategy for a new app or major update. Also use when the user mentions "app launch", "launch plan", "launch checklist", "pre-launch", "launch day", or "how to launch my app". For ongoing ASO after launch, see aso-audit. For paid acquisition during launch, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to analyze their own app's actual performance data from App Store Connect — real downloads, revenue, IAP, subscriptions, trials, or country breakdowns synced via Appeeky Connect. Use when the user asks about "my downloads", "my revenue", "how is my app performing", "ASC data", "sales and trends", "my subscription numbers", "App Store Connect metrics", or wants to compare periods or top markets. For third-party app estimates, see app-analytics. For subscription analytics depth, see monetization-strategy.

JordanCoin/ios-skills-collection

When the user wants a full ASO health audit, review their App Store listing quality, or diagnose why their app isn't ranking. Also use when the user mentions "ASO audit", "ASO score", "why am I not ranking", "listing review", or "optimize my app store page". For keyword-specific research, see keyword-research. For metadata writing, see metadata-optimization.

JordanCoin/ios-skills-collection

Always use when working on any iOS, macOS, Swift, SwiftUI, Xcode, or Apple platform project. Routes to the correct specialized skills based on development phase and task context. This collection contains 210 skills from 28 authors covering the full iOS lifecycle.

Verwandte Skills