Pattern · Sheets and Alerts

New

Permission Primer SwiftUI Block

Explain-then-ask for notifications, location, the camera or photos, then answer what iOS says: granted, or Open Settings.

A primer shown before a system permission prompt. It explains why the app needs the permission, lists what it makes possible, draws the alert iOS will show next, then requests the real permission. Granted turns to a check and calls back; denied explains where to change it and offers Open Settings, and turns granted when the person comes back having allowed it.

  • SwiftUI
  • iOS 17.0+
  • permission-primer
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • One large symbol, the reason and two or three benefits
  • A drawing of the alert iOS shows next, so the prompt is no surprise
  • Continue requests the real permission for notifications, location, camera or photos
  • Granted shows a check and calls onGranted; denied offers Open Settings
  • Reads the current status on appear and again on return from Settings

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

One large SF Symbol (not in a tile), a title in the display face and the reason in a sentence, then a card of two or three things the permission makes possible, each with a symbol, a short title and a line. Under it, a small drawing of the alert iOS will show next, with its title, message and buttons, so the system prompt is no surprise. Continue requests the real permission: notifications through UNUserNotificationCenter, location through CLLocationManager, the camera through AVCaptureDevice and photos through PHPhotoLibrary. It shows progress while the system alert is up. Granted shows a check on Continue, then the symbol turns into a check in the success colour, the words change ("Notifications are on") and onGranted runs. Denied changes the symbol to its off form, says where to turn it on, and offers Open Settings; when the person comes back having turned it on, the block turns granted by itself. Not now leaves without asking, so the system's one prompt is kept for a better moment. The block reads the current status as it appears, so a permission already granted or denied opens on that state.

Notes

  • PermissionPrimer(kind:content:onGranted:onNotNow:request:) takes a Kind (.notifications, .location, .camera, .photos) and everything else is optional.
  • It is a section: no scroll view, background or padding of its own. Use it inline in a screen's column, or as a sheet's content in a ScrollView with 20 point margins.
  • PermissionPrimer.Content holds the symbol, title, reason, benefits (each a Benefit with symbol, title and detail), the Continue title, the sample alert's title, message and button labels, and the granted and denied titles and lines. Content.standard(for:appName:) gives plain defaults for each kind, naming your app from CFBundleDisplayName and reading the sample alert's message from your purpose string. Start from it and change what you need. Content.sample is the notifications primer from the preview.
  • onGranted(Status) runs about a second after the permission is granted, with .granted or, for photos, .limited; dismiss the sheet or move on there. Granted also shows Done, which calls it again, for inline use.
  • onNotNow defaults to dismissing the presenting sheet.
  • request replaces the system request, for example to ask for provisional notifications or go through your own permission service. Return a Status (.notDetermined, .granted, .limited, .denied). With it set, the block doesn't read the current status on appear. A thrown LocalizedError shows its message under Continue.
  • Notifications ask for alerts, badges and sounds. Location asks for when-in-use; the block keeps its CLLocationManager alive until the answer comes. Photos ask for read and write access.
  • Open Settings opens UIApplication.openSettingsURLString with openURL.
  • Haptics: success on granted, a warning on denied.
  • VoiceOver reads the sample alert as one line ("Next, iOS asks: ..."), each benefit as one element, announces the result, and reads Continue as "Waiting for your answer" while the system alert is up. Text grows with Dynamic Type; the symbol and the sample alert stop growing at large sizes so the words keep the room.
  • Reduce Motion turns the symbol change and state changes into short fades.
  • PermissionPrimerExample at the end of PermissionPrimer.swift is a Reminders screen that primes notifications in a sheet as it opens and reads On once allowed. Pass wrapsInNavigationStack: false to push it in your own stack.
  • The real system alert can't be shown in a preview. The web preview's alert is a stand-in for it.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • The title is the one display moment: type.face at 28 points, type.displayWeight capped at semibold, in textPrimary, falling back to type.textDesign when figures are monospaced. The reason is type.subhead in textSecondary.
  • The symbol is 52 points regular in textPrimary, success when granted and textSecondary when denied.
  • The benefits card is color.surface at radius.lg with separator hairlines inset to the text; its symbols are textSecondary, titles type.subhead semibold, lines type.footnote.
  • The sample alert is surfaceElevated with a separator stroke, type.footnote and type.caption.
  • Continue (then Done or Open Settings) is the only accent: accent with accentOn in type.headline at radius.md. Not now is a plain textPrimary button. Errors are danger.
  • Groups sit 24 points apart (space.xl); changes use motion.smooth and motion.snappy.

Requirements

  • The purpose string for the kind you ask for: NSLocationWhenInUseUsageDescription, NSCameraUsageDescription or NSPhotoLibraryUsageDescription. Notifications need no key.