我希望创建一个属性来跟踪用户对应用程序的通知授权设置。(这里的最终目标是提醒用户,如果他们要求通知,但拒绝从应用程序接收通知。)我尝试了各种解决方案,但都没有成功。下面的代码抛出一个错误,上面写着";无法将类型为"Void"的返回表达式转换为返回类型"String"。
class LocalNotificationScheduler {
var notificationAuthStatus: String {
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .authorized:
return "authorized"
case .provisional:
return "provisional"
case .notDetermined:
return "notDetermined"
case .denied:
return "denied"
default:
break
} // End of "switch settings.authorizationStatus {"
} // End of "{ settings in"
}
private func requestAuthorization() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted == true && error == nil {
self.scheduleNotification()
}
}
} // End of requestAuthorization() func
func schedulingRequested() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .notDetermined:
self.requestAuthorization()
case .authorized, .provisional:
self.scheduleNotification()
case .denied:
print("Conflict between request for notification and app permissions!")
default:
break
}
}
} // End of schedule() func
private func scheduleNotification() {
let content = UNMutableNotificationContent()
content.title = "Scheduled notification"
content.body = "Test"
content.sound = .default
// Trigger
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else { return }
}
} // End of scheduleNotification() func
// MARK: - Life Cycle
init() {
} // End of init()
}
struct ContentView: View {
// MARK: - Properties
// Alert the user that there's a conflict between their request for a notification and the app permissions
@State var notificationConflict: Bool = false
// MARK: - View
var body: some View {
Form {
Button("Send notification") {
let notificationScheduler = LocalNotificationScheduler()
print("Step 1: notificationScheduler.notificationAuthStatus = (notificationScheduler.notificationAuthStatus)")
if notificationScheduler.notificationAuthStatus == "denied" {
notificationConflict = true
print("Step 2a: notificationScheduler.notificationAuthStatus WAS denied so...")
print("notificationConflict = (notificationConflict)")
} else {
print("Step 2b: notificationScheduler.notificationAuthStatus was NOT denied so scheduling notification")
notificationScheduler.schedulingRequested()
}
print("Step 3: notificationScheduler.notificationAuthStatus = (notificationScheduler.notificationAuthStatus)")
print("Step 3: notificationConflict = (notificationConflict)")
}
} // End of Form
} // End of body view
}
我还尝试创建一个函数,它看起来很像上面的代码,但设置了notificationAuthStatus
的值,而不是返回它。该函数不会抛出错误,但它异步运行,因此当我需要使用它时,不会设置notificationAuthStatus
的值。
任何关于如何进行的建议都将不胜感激!
编译:
var notificationAuthStatus: String {
var status = "notDetermined"
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .authorized:
status = "authorized"
case .provisional:
status = "provisional"
case .notDetermined:
status = "notDetermined"
case .denied:
status = "denied"
default:
break
} // End of "switch settings.authorizationStatus {"
} // End of "{ settings in"
return status
}
但我不知道这是否足以满足您的代码,因为您没有在上下文中显示它,所以我们不知道您是如何使用它的。
如果你在通知控制器类中使用它来查看你是否有授权,或者是否需要请求授权,为什么不直接使用它而不是返回字符串呢?
我想我已经想出了一个适合我的解决方案。我把它贴在这里,以防其他人遇到同样的挑战并偶然发现这个问题。以下是对我有效的方法:
- 使用方法而不是计算属性来确定notification.authorizationStatus
- 在初始化LocalNotificationScheduler类的实例和请求通知时都调用该方法。如果用户更改设置,此组合似乎可以处理通知的中途更改。authorizationStatus
- 在加载视图时初始化LocalNotificationScheduler类,而不是在用户请求通知时初始化。这意味着应用程序可能会有一些不必要的开销——在不需要的时候创建LocalNotificationScheduler的实例——但它也适应了检查.authorizationStatus的时间滞后,这可能会导致使用.authoriizationStatus的属性无法立即更新
这是我的LocalNotificationScheduler代码:
class LocalNotificationScheduler {
var notificationAuthStatusDenied: Bool = false
// MARK: - Methods
func determineAuthStatus() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .authorized, .provisional, .notDetermined:
self.notificationAuthStatusDenied = false
case .denied:
self.notificationAuthStatusDenied = true
default:
break
} // End of "switch settings.authorizationStatus {"
} // End of "{ settings in"
} // End of determineAuthStatus() func
private func requestAuthorization() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted == true && error == nil {
self.scheduleNotification()
}
}
} // End of requestAuthorization() func
func schedulingRequested() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .notDetermined:
self.requestAuthorization()
case .authorized, .provisional:
self.scheduleNotification()
case .denied:
print("Conflict between request for notification and app permissions!")
default:
break
}
}
} // End of schedule() func
private func scheduleNotification() {
let content = UNMutableNotificationContent()
content.title = "Scheduled notification"
content.body = "Test"
content.sound = .default
// Trigger
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else { return }
}
} // End of scheduleNotification() func
// MARK: - Life Cycle
init() {
determineAuthStatus()
} // End of init()
}
和视图代码:
struct ContentView: View {
// MARK: - Properties
var notificationScheduler = LocalNotificationScheduler()
// Alert the user that there's a conflict between their request for a notification and the app permissions
@State var notificationConflictAlertNeeded: Bool = false
// MARK: - View
var body: some View {
Form {
Button("Send notification") {
// Re-check .authorizationStatus - this doesn't complete until the code below has run,
// hence the need to first check .authorization status when the notificationScheduler property is initialized.
// This does mean that the app re-checks the .authorizationStatus and can detect a change during app use
notificationScheduler.determineAuthStatus()
// Either schedule the notification or set the flag indicating that this isn't possible
if notificationScheduler.notificationAuthStatusDenied == false {
notificationScheduler.schedulingRequested()
} else {
notificationConflictAlertNeeded = true
}
}
} // End of Form
} // End of body view
}
所以,这就是我目前的解决方案。如果有更好的方法来完成这一切,我欢迎您的参与!