How does one send notification in vision os? I seem to not be able to find any information about notifications in vision os.
I have a window which after some time it should alert the user to look at it and I thought notification is a good idea (or is there some other way I could do that?) but I can't get it to work.
I have the permission requested and granted. Am I doing something wrong? Is vision os not supporting notifications? I can't find anything related to this. Did anyone manage to send a notification and if yes, how?
I tried the following code and it does not do anything:
let content = UNMutableNotificationContent()
content.title = "Feed the cat"
content.body = "It looks hungry"
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request)
You are missing the delegate
and telling the UNUserNotificationCenter
how to present the notification in the foreground.
extension NotificationManager: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
.banner
}
}
The rest of the manager
would look something like.
@Observable final class NotificationManager: NSObject {
private(set) var isPermissionGranted = false
let userNC = UNUserNotificationCenter.current()
override init() {
super.init()
userNC.delegate = self
}
func sendNotifications() async throws {
let id = UUID().uuidString
let content = UNMutableNotificationContent()
content.title = "Let's feed the cat"
content.subtitle = "It looks hungry"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: true)
let request = UNNotificationRequest(identifier: id,content: content,trigger: trigger)
try await userNC.add(request)
print("\(#function) :: scheduled")
}
func requestAuthorization () async throws {
do {
isPermissionGranted = try await userNC.requestAuthorization(options: [.alert, .badge, .sound])
} catch {
print(error)
}
}
func cancelAll() {
userNC.removeAllPendingNotificationRequests()
}
}
Note that you should create the manager
at the very top of your app with
@State private var manager: NotificationManager = .init()
and inject it into the app with
.environment(manager)
So you can access it everywhere with
@Environment(NotificationManager.self) private var manager
It is important that the delegate
is stable so the app doesn't miss notifications.
Here is a sample View
import SwiftUI
import RealityKit
import UserNotifications
struct NotificationSample: View {
@Environment(NotificationManager.self) private var manager
@State private var date: Date?
@State private var isScheduling: Bool = false
var body: some View {
RealityView { content, attchments in
guard let attachment = attchments.entity(for: "Feed") else {return}
content.add(attachment)
} update: { content, attchments in
} attachments: {
Attachment(id: "Feed") {
VStack {
if let date {
Text(date, style: .timer)
}
Button("FEED THE CAT") {
isScheduling.toggle()
}.task(id: isScheduling) {
guard isScheduling else {return}
do {
try await manager.sendNotifications()
} catch {
print(error)
}
isScheduling = false
date = Calendar.current.date(byAdding: .minute, value: 1, to: Date())
}.disabled(!manager.isPermissionGranted)
}
}
}
.task {
do {
try await manager.requestAuthorization()
} catch {
print(error)
}
manager.cancelAll()
}
}
}