Permissions are not dialogs.
They are state machines with legal consequences.
Most apps get this wrong:
- permission prompts appear too early
- users tap “Don’t Allow” permanently
- features silently fail
- UX feels pushy or broken
- privacy trust is lost
This post shows how to design permission & privacy architecture in SwiftUI that is:
- predictable
- respectful
- testable
- compliant
- reversible where possible
🧠 The Core Principle
The system dialog is the last step — not the first.
If the first time a user learns why you need access is the OS alert, you already failed.
🧱 1. Model Permissions as State Machines
Never treat permissions as booleans.
Bad:
if hasCameraPermission { ... }
Correct:
enum PermissionState {
case unknown
case explained
case requesting
case granted
case denied
case restricted
}
Your app logic depends on state, not just access.
🧭 2. Central Permission Coordinator
Permissions must live in infrastructure, not features.
protocol PermissionService {
func state(for permission: Permission) -> PermissionState
func request(_ permission: Permission)
}
This allows:
- consistent flows
- testability
- auditability
- UI reuse
Views never talk to system APIs directly.
🧬 3. Explain Before Requesting
Always show a pre-permission screen:
- what is needed
- why it’s needed
- what happens if declined
- reassurance about privacy
Only after user intent:
permissionService.request(.camera)
This dramatically improves grant rates.
🔐 4. Request Once — Handle Denials Gracefully
iOS will not re-prompt after denial.
Your architecture must:
- detect denial
- explain consequences
- offer Settings redirect
- provide fallback behavior
case .denied:
showSettingsEducation()
Never spam prompts.
🧪 5. Permission Testing Strategy
Permissions must be testable without system dialogs.
final class MockPermissionService: PermissionService {
var states: [Permission: PermissionState]
}
You can now test:
- first launch
- denial flows
- restricted devices
- upgrade scenarios
🧠 6. Privacy-First Feature Design
Design features to:
- degrade gracefully
- work partially without permission
- avoid blocking entire flows
- never crash on denial
If denial breaks your app, the architecture is wrong.
🧾 7. Privacy Disclosures Are Architecture
Your:
- Info.plist strings
- onboarding copy
- UI explanations
must match actual usage.
Mismatches create:
- App Store rejection
- legal exposure
- user distrust
Keep disclosures versioned and reviewed.
⚠️ 8. Common Permission Anti-Patterns
Avoid:
- requesting on app launch
- requesting multiple permissions at once
- hiding functionality silently
- retrying prompts
- treating denial as error
- tying permission logic to views
These permanently damage trust.
🧠 Mental Model
Think:
Need Identified
→ Explanation
→ User Intent
→ System Prompt
→ State Handling
Not:
“Just ask for it”
🚀 Final Thoughts
Correct permission architecture gives you:
- higher opt-in rates
- fewer denials
- safer compliance
- clearer UX
- long-term trust
Permissions are not obstacles.
They are conversations.
Top comments (0)