我想在我的 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)
}
}
}
}
您无法以编程方式从通知中“取消授权”,因此我假设您在
@AppStorage
或其他位置存储了一个标志,指示用户是否更喜欢收到通知。
@AppStorage("notifications") var shouldSendNotifications = true
仅当
shouldSendNotifications
为 true 并且 用户已授权您的应用程序时,您才应发送通知。
notificationSettings
获取当前的授权状态,并用您获得的状态更新一些 @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()
}
}
}