ForgePushPermission
Request push authorization, check the current status, and deep-link into Settings.
PushPermission
A Sendable struct wrapping UNUserNotificationCenter. Methods: request(_:), status(), openSettings().
request(_:)
Presents the system authorization prompt. Defaults to [.alert, .badge, .sound]. Returns whether the user granted permission. Marked @discardableResult.
import ForgePushPermission
let permission = PushPermission()
// Request authorization (alert, badge, sound by default)
let granted = try await permission.request() // Request with custom options
let granted = try await permission.request([.alert, .badge, .sound, .provisional]) status()
Returns the current UNAuthorizationStatus without triggering any prompts.
let permission = PushPermission()
switch await permission.status() {
case .authorized:
print("Push is enabled")
case .denied:
await permission.openSettings()
case .notDetermined:
try await permission.request()
case .provisional:
print("Provisional — quiet delivery")
case .ephemeral:
print("App Clip context")
@unknown default:
break
} openSettings()
Opens the app's page in iOS Settings. Runs on @MainActor. Use this when the user has denied permission and needs to re-enable it manually.
let permission = PushPermission()
if await permission.status() == .denied {
await permission.openSettings()
} Note: PushPermission does not register for remote notifications. Use PushTokenManager.registerForRemoteNotifications() from ForgePushToken to trigger the APNs registration flow after the user grants permission.
Full Flow
A typical pattern that handles all authorization states:
import ForgePushPermission
import ForgePushToken
final class TaskFlowNotificationsManager {
private let permission = PushPermission()
private let tokenManager: PushTokenManager
init(tokenManager: PushTokenManager) {
self.tokenManager = tokenManager
}
func enableNotifications() async throws {
let status = await permission.status()
switch status {
case .notDetermined:
try await permission.request()
await tokenManager.registerForRemoteNotifications()
case .authorized, .provisional:
await tokenManager.registerForRemoteNotifications()
case .denied:
await permission.openSettings()
default:
break
}
}
}