我使用这些两个类来管理应用程序中的本地通知,问题是当我点击通知操作按钮“标记为已完成”时,它没有执行该操作,只是将我带到应用程序,所以我如何才能使通知操作按钮响应该操作?
通知管理器类
internal final class LocalNotificationManager {
private static let center = UNUserNotificationCenter.current()
// MARK: Ask for permission
static func askUserPermissionToSendNotifications() {
self.center.requestAuthorization(options: [.alert, .badge, .sound]) { (success, error) in
if success {
// Do something if user allowing notifications
} else if !success {
// Do something if user do not allow the notifications
} else if let error = error {
// Show some message
print(error.localizedDescription)
}
}
}
// MARK: Schedul Notification
static func schedulNotification(for taskModel: TaskModel) {
let content = UNMutableNotificationContent()
content.interruptionLevel = .timeSensitive
content.body = taskModel.text
content.subtitle = "\(taskModel.priority != .none ? "\(taskModel.priority.rawValue) Priority" : "")"
content.categoryIdentifier = "Task Actions" // Same Identifier in registerCategories()
content.sound = UNNotificationSound.default
let taskIdentifier = taskModel.id.uuidString
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: taskIdentifier, content: content, trigger: trigger)
let localNotificationDelegate = LocalNotificationDelegate()
self.center.delegate = localNotificationDelegate
let markAsCompleted = UNNotificationAction(identifier: "MARK_AS_COMPLETED", title: "Mark as Completed", options: .foreground)
let placeholder = "Task"
let category = UNNotificationCategory(identifier: "Task Actions", actions: [markAsCompleted], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: placeholder) // // Same Identifier in schedulNotification()
self.center.setNotificationCategories([category])
self.center.add(request)
}
}
通知委托
internal final class LocalNotificationDelegate: NSObject, ObservableObject, UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == "MARK_AS_COMPLETED" {
// its didn't print the message when I tap the action button
print("MARK_AS_COMPLETED Tapped")
}
completionHandler()
}
}
我花了 1 小时与 SwiftUI 对抗后的两分钱。 (注意:文档有点缺乏......)
(坦克到https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-an-appdelegate-to-a-swiftui-app)
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
即便如此,没有“可选”委托调用它也不起作用..所以你必须至少实现:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
现在是我的完整代码:(我知道并不总是很好,但对于初学者来说,只需复制/粘贴即可使其工作。)
我在通话中添加了一些注释和变体。
-- 应用程序 --
import SwiftUI
@main
struct LocalNotificationSwiftUIApp: App {
// tanks to https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-an-appdelegate-to-a-swiftui-app
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
// app delegate:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// print("Your code here")
let nc = UNUserNotificationCenter.current()
// if You do not set delegate, does not work.
nc.delegate = self
return true
}
// called after user has tapped on notification ballon.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let request = notification.request
//let content = request.content
let identifier = request.identifier
//let title = content.title
//print(title)
print( identifier,"\n----\n")
completionHandler([.banner, .list, .badge, .sound])
} // end of userNotificationCenter
}
}
-- 内容视图
import SwiftUI
import UserNotifications
struct ContentView: View {
var body: some View {
VStack{
Button("SCHEDULE", action: schedule)
}
.onAppear(perform: prepareForNotifications)
}
func prepareForNotifications(){
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
print("\(granted)")
if granted {
// run automatically... on run
self.schedule()
}
}
} // end of prepareForNotifications
func schedule() {
let NOTIFICATION_DELAY = 5.0 // if repeating, min is 60 secs.
let NOTIFICATION_ID = "NOTIFICATION_ID" // note: if repeating, ID must be differr, otherwise IOS will consider only once with this ID
let USE_INTERVAL = true // experiment..
let content = UNMutableNotificationContent()
content.title = "Hello!"
content.body = "Hello message body"
content.sound = UNNotificationSound.default
content.badge = 1
let center = UNUserNotificationCenter.current()
if USE_INTERVAL{
let trigger = UNTimeIntervalNotificationTrigger.init(
timeInterval: NOTIFICATION_DELAY,
//repeats: true // if true, min 60 secs.
repeats: false
)
let request = UNNotificationRequest.init(identifier: NOTIFICATION_ID,
content: content,
trigger: trigger)
// Schedule the notification.
center.add(request)
}else{
// USE DATE:
let date = Date(timeIntervalSinceNow: 5)
let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second,], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate,
repeats: true)
let request = UNNotificationRequest.init(identifier: NOTIFICATION_ID,
content: content,
trigger: trigger)
// Schedule the notification.
center.add(request)
}
}
}
通过观看 Kavsoft 的视频,我能够向 SwiftUI 视图添加可操作的通知
struct ContentView: View {
@StateObject var delegate = NotificationDelegate()
var body: some View {
Button(action: createNotification) {
Text("Notify User")
}
.onAppear {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
}
UNUserNotificationCenter.current().delegate = delegate
}
.alert(isPresented: $delegate.alert) {
Alert(title: Text("Message"), message: Text("Reply Button is pressed"), dismissButton: .destructive(Text("Ok")))
}
}
func createNotification() {
let content = UNMutableNotificationContent()
content.title = "Message"
content.subtitle = "Hello, world!"
content.categoryIdentifier = "ACTIONS"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "IN-APP", content: content, trigger: trigger)
let close = UNNotificationAction(identifier: "CLOSE", title: "Close", options: .destructive)
let reply = UNNotificationAction(identifier: "REPLY", title: "Reply", options: .foreground)
let category = UNNotificationCategory(identifier: "ACTIONS", actions: [close, reply], intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
class NotificationDelegate: NSObject, ObservableObject, UNUserNotificationCenterDelegate {
@Published var alert = false
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.badge, .banner, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == "REPLY" {
print("reply or do something else")
self.alert.toggle()
}
completionHandler()
}
}