SwiftUI 使用应用程序的本地通知创建属性 .authorizationStatus



我希望创建一个属性来跟踪用户对应用程序的通知授权设置。(这里的最终目标是提醒用户,如果他们要求通知,但拒绝从应用程序接收通知。)我尝试了各种解决方案,但都没有成功。下面的代码抛出一个错误,上面写着";无法将类型为"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
}

但我不知道这是否足以满足您的代码,因为您没有在上下文中显示它,所以我们不知道您是如何使用它的。

如果你在通知控制器类中使用它来查看你是否有授权,或者是否需要请求授权,为什么不直接使用它而不是返回字符串呢?

我想我已经想出了一个适合我的解决方案。我把它贴在这里,以防其他人遇到同样的挑战并偶然发现这个问题。以下是对我有效的方法:

  1. 使用方法而不是计算属性来确定notification.authorizationStatus
  2. 在初始化LocalNotificationScheduler类的实例和请求通知时都调用该方法。如果用户更改设置,此组合似乎可以处理通知的中途更改。authorizationStatus
  3. 在加载视图时初始化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
}

所以,这就是我目前的解决方案。如果有更好的方法来完成这一切,我欢迎您的参与!

最新更新