Я хотел бы добавить универсальный переключатель «Push-уведомления» в свой SettingsView.
Под универсальным я подразумеваю, что я хотел бы, чтобы переключатель автоматически устанавливался в положение «включено», если текущее разрешение уведомления приложения является авторизованным, временным или эфемерным. И отключается, если отказано или не определено.
В идеале переключатель также будет запрашивать разрешение, если установлено значение «не определено». И отправьте в настройки приложения, если установлено значение «отказано».
Фрагмент моего просмотра настроек
struct SettingsView: View {
let notify = NotificationHandler()
@State private var enablePushNotifications = false
var body: some View {
NavigationView {
Form {
Section(header: Text("Notifications")) {
let toggle = Binding<Bool> (
get: { self.enablePushNotifications }
set: { newValue in
self.enablePushNotifications = newValue
})
Toggle("Push Notifications", isOn: toggle)
}
}
}
}
Спасибо! Я был в стороне от девальвации. Я обновился, чтобы использовать NavigationStack.
Вы не можете программно «отключить» себя от уведомлений, поэтому я предполагаю, что у вас есть флаг, хранящийся в @AppStorage
или где-то еще, который указывает, предпочитает ли пользователь получать уведомления.
@AppStorage("notifications") var shouldSendNotifications = true
Отправлять уведомления следует только тогда, когда shouldSendNotifications
истинно и пользователь авторизовал ваше приложение.
Затем все, что вам нужно сделать, это получить текущий статус авторизации с помощью Настройки уведомлений и обновить некоторые @State
полученным статусом. Вы можете запустить этот код в блоке task(id:)
, чтобы его можно было запустить повторно, просто изменив id
.
@preconcurrency import UserNotifications
struct ContentView: View {
@State private var notificationAuthorised = false
@State private var taskTrigger = false
@Environment(\.scenePhase) var scenePhase
@AppStorage("notifications") var shouldSendNotifications = true
var body: some View {
Form {
Section(header: Text("Notifications")) {
let binding = Binding {
notificationAuthorised && shouldSendNotifications
} set: { newValue in
if newValue { // turning on notifications
Task {
// perhaps also UIApplication.shared.registerForRemoteNotifications()
shouldSendNotifications = true
let notifCenter = UNUserNotificationCenter.current()
let settings = await notifCenter.notificationSettings()
if settings.authorizationStatus == .notDetermined {
// show the request alert
try await notifCenter.requestAuthorization(options: [.alert, .sound, .badge])
} else if settings.authorizationStatus == .denied {
// go to settings page
if let appSettings = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(appSettings) {
await UIApplication.shared.open(appSettings)
}
}
// run the task again to update notificationAuthorised
taskTrigger.toggle()
}
} else {
shouldSendNotifications = false
// perhaps also UIApplication.shared.unregisterForRemoteNotifications()
}
}
Toggle("Push Notifications", isOn: binding)
}
}
.task(id: taskTrigger) {
let notifCenter = UNUserNotificationCenter.current()
let settings = await notifCenter.notificationSettings()
switch settings.authorizationStatus {
case .notDetermined, .denied:
notificationAuthorised = false
case .authorized, .ephemeral, .provisional:
notificationAuthorised = true
@unknown default:
notificationAuthorised = false
}
}
// run the task again to update notificationAuthorised when coming back to the app
.onChange(of: scenePhase) {
taskTrigger.toggle()
}
}
}
Это именно то решение, которое мне было нужно! Мой переключатель уведомлений теперь универсален :)
Обратите внимание:
NavigationView
устарел, вам следует использоватьNavigationStack
. Почему бы не использоватьenablePushNotifications
напрямую, напримерToggle("Push Notifications", isOn: $enablePushNotifications)
.