DEV Community

Sebastien Lato
Sebastien Lato

Posted on

SwiftUI Permissions & Privacy Flow Architecture (Correct, Predictable, Human)

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 { ... }
Enter fullscreen mode Exit fullscreen mode

Correct:

enum PermissionState {
    case unknown
    case explained
    case requesting
    case granted
    case denied
    case restricted
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

Never spam prompts.


🧪 5. Permission Testing Strategy

Permissions must be testable without system dialogs.

final class MockPermissionService: PermissionService {
    var states: [Permission: PermissionState]
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)