From apple-dev
Generates GDPR/CCPA/DPDP privacy consent flows with granular category preferences, consent state persistence, audit logging, and ATT (App Tracking Transparency) integration. Use when user needs privacy consent UI, cookie/tracking consent, or compliance management.
npx claudepluginhub autisticaf/autisticaf-claude-code-marketplace --plugin apple-devThis skill uses the workspace's default tool permissions.
> **First step:** Tell the user: "generators-consent-flow skill loaded."
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
First step: Tell the user: "generators-consent-flow skill loaded."
Generate a production privacy consent system with granular category-based consent, persistent state management, a consent banner and preferences UI, audit logging for compliance, and App Tracking Transparency integration.
Use this skill when the user:
Search for existing consent or privacy code:
Glob: **/*Consent*.swift, **/*Privacy*.swift, **/*Tracking*.swift, **/*GDPR*.swift
Grep: "ATTrackingManager" or "ConsentManager" or "trackingAuthorizationStatus"
If third-party library found (OneTrust, Usercentrics, CookieBot):
Check for App Tracking Transparency framework:
Grep: "AppTrackingTransparency" in project files
Grep: "NSUserTrackingUsageDescription" in Info.plist
If NSUserTrackingUsageDescription is missing from Info.plist, warn the user that ATT requires this key and offer to add it.
Determine if generating for iOS (primary ATT target) or macOS (ATT not applicable) or both.
Ask user via AskUserQuestion:
Target regulations?
Consent categories? (multi-select)
Include ATT integration?
Consent UI style?
Read templates.md for production Swift code.
Read references/patterns.md for compliance rules, regulation differences, and UX guidance.
Generate these files:
ConsentCategory.swift — Enum of consent categories with metadataConsentDecision.swift — Per-category consent state with timestampConsentManager.swift — @Observable manager with persistence and ATT integrationConsentAuditLog.swift — Compliance audit trail with JSON exportConsentBannerView.swift — Animated slide-up consent bannerConsentPreferencesView.swift — Detailed toggle list for each categoryBased on configuration:
ConsentRegulationConfig.swift — If multiple regulations selectedConsentATTBridge.swift — If ATT integration selected (extracted for testability)Check project structure:
Sources/ exists → Sources/Consent/App/ exists → App/Consent/Consent/After generation, provide:
Consent/
├── ConsentCategory.swift # Consent category enum with metadata
├── ConsentDecision.swift # Per-category decision with timestamp
├── ConsentManager.swift # @Observable manager with persistence
├── ConsentAuditLog.swift # Compliance audit trail
├── ConsentBannerView.swift # Animated consent banner
├── ConsentPreferencesView.swift # Granular preferences UI
├── ConsentRegulationConfig.swift # Multi-regulation rules (optional)
└── ConsentATTBridge.swift # ATT integration bridge (optional)
Show consent on first launch:
@main
struct MyApp: App {
@State private var consentManager = ConsentManager()
var body: some Scene {
WindowGroup {
ContentView()
.environment(consentManager)
.overlay(alignment: .bottom) {
if consentManager.needsConsent {
ConsentBannerView()
.environment(consentManager)
.transition(.move(edge: .bottom).combined(with: .opacity))
}
}
.animation(.easeInOut(duration: 0.3), value: consentManager.needsConsent)
}
}
}
Check consent before tracking:
func trackEvent(_ event: AnalyticsEvent) {
guard consentManager.hasConsent(for: .analytics) else { return }
analyticsService.track(event)
}
func showPersonalizedAd() {
guard consentManager.hasConsent(for: .marketing) else {
showGenericAd()
return
}
adService.showPersonalized()
}
Open preferences from settings:
NavigationLink("Privacy Preferences") {
ConsentPreferencesView()
.environment(consentManager)
}
Export audit log for data requests:
func handleDataRequest() async throws -> Data {
let auditLog = ConsentAuditLog.shared
return try auditLog.exportJSON()
}
@Test
func consentGrantedPersistsAcrossLaunches() async {
let defaults = UserDefaults(suiteName: "test")!
defaults.removePersistentDomain(forName: "test")
let manager = ConsentManager(defaults: defaults)
manager.updateConsent(for: .analytics, granted: true)
let manager2 = ConsentManager(defaults: defaults)
#expect(manager2.hasConsent(for: .analytics) == true)
}
@Test
func essentialConsentCannotBeRevoked() {
let manager = ConsentManager()
manager.updateConsent(for: .essential, granted: false)
#expect(manager.hasConsent(for: .essential) == true) // Always granted
}
@Test
func auditLogRecordsDecisions() {
let log = ConsentAuditLog(directory: tempDirectory)
log.record(category: .analytics, granted: true, regulation: .gdpr)
let entries = log.allEntries()
#expect(entries.count == 1)
#expect(entries[0].category == .analytics)
#expect(entries[0].granted == true)
}
@Test
func denyAllRevokesNonEssentialCategories() {
let manager = ConsentManager()
manager.grantAll()
manager.denyAllNonEssential()
#expect(manager.hasConsent(for: .essential) == true)
#expect(manager.hasConsent(for: .analytics) == false)
#expect(manager.hasConsent(for: .marketing) == false)
}
.onAppear {
if consentManager.needsConsent {
// Banner auto-shows via overlay
}
}
Button("Privacy Settings") {
showPreferences = true
}
.sheet(isPresented: $showPreferences) {
ConsentPreferencesView()
.environment(consentManager)
}
extension ConsentManager {
func executeIfConsented(
category: ConsentCategory,
action: () -> Void
) {
guard hasConsent(for: category) else { return }
action()
}
}
let jsonData = try consentManager.auditLog.exportJSON()
// Attach to email or upload to compliance endpoint
Apple rejects apps that access IDFA before calling ATTrackingManager.requestTrackingAuthorization. Always request ATT first, then enable tracking SDKs based on the result.
Under GDPR, all non-essential tracking requires explicit opt-in consent. Pre-checked boxes or implied consent are not valid. The default state for all non-essential categories must be .notDetermined, not .granted.
GDPR Article 7(3): "It shall be as easy to withdraw as to give consent." If consent is granted with one tap on a banner, it must be revocable with equal ease — not buried 5 screens deep in settings.
If your app serves minors, you need age verification before consent collection.
ATTrackingManager.requestTrackingAuthorization is async and shows a system dialog. Never call it during app launch or in a way that blocks the main UI. Show your own consent banner first, then request ATT as a secondary step.
For GDPR compliance, consider syncing consent state to a server. UserDefaults is deleted on app uninstall. If a user reinstalls, you must re-request consent — never assume prior consent.
generators-permission-priming — Pre-permission UI patterns (ATT priming)generators-analytics-setup — Analytics that respects consent stategenerators-settings-screen — Embedding consent preferences in settings