Reputation: 363
I’m developing a game that offers free gems every day. The app checks if the gems have been claimed, and if they haven’t, it displays a badge with a count of 1. Once the gems are claimed, the current date is stored in an array lastClaimDate to prevent the player from claiming gems again on the same day.
I want to send a notification if the gems have not been claimed yet. I attempted to do this using the sendNotification() function, which should display a notification banner at the top of the screen once the function canGemsBeClaimed would return true, but this did not trigger.
Because I couldn’t get this to work, I switched to trying a simpler approach: sending a notification at midnight using sendMidnightNotification(). The idea is that every morning, the user would see a notification that gems can be claimed, this works.
The final goal should be that the user gets a notification at 9 AM that gems can be claimed if he did not claim the gems between midnight and 9 AM and should only pop up at that time. My tries resulted in either no pop up at all, or it would always show despite if gems have been claimed before or not.
So what should I do to modify the code properly? I believe there might be some logic issues in the current code which I need to rework. I am not experienced with background tasks when the app is closed, therefore guidance would help. Thanks a lot!
Here’s the relevant code:
import SwiftUI
import BackgroundTasks
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
@AppStorage("lastClaimDate") private var lastClaimDate: [String] = [""]
private var currentDateString: String {
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter.string(from: currentDate)
}
func canGemsBeClaimed() -> Bool {
return !lastClaimDate.contains(currentDateString)
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "ijouClaimGemsNotification", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
sendMidnightNotification()
// Request notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if let error = error {
print("Notification permission error: \(error)")
}
}
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
scheduleAppRefresh()
}
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "ijouClaimGemsNotification")
request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 60) // 60 seconds
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleAppRefresh(task: BGAppRefreshTask) {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
scheduleAppRefresh()
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 5
let operation = BlockOperation {
if self.canGemsBeClaimed() {
self.sendNotification()
self.setBadgeCount(1)
} else {
self.setBadgeCount(0)
}
}
task.expirationHandler = {
queue.cancelAllOperations()
}
operation.completionBlock = {
task.setTaskCompleted(success: !operation.isCancelled)
}
queue.addOperation(operation)
}
func sendMidnightNotification() {
// Create the notification content
let content = UNMutableNotificationContent()
content.title = "New Gems Available"
content.body = "New gems can be claimed."
content.sound = .default
content.badge = 1
// Set up the trigger to fire at midnight
var dateComponents = DateComponents()
dateComponents.hour = 0 // Midnight (00:00)
dateComponents.minute = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// Create the request
let request = UNNotificationRequest(identifier: "MidnightGemsNotification", content: content, trigger: trigger)
// Schedule the notification
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Error scheduling notification: \(error)")
}
}
}
func sendNotification() {
let content = UNMutableNotificationContent()
content.title = "Gems Available"
content.body = "You can now claim new gems!"
content.sound = .default
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "GemsNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
func setBadgeCount(_ count: Int) {
UNUserNotificationCenter.current().setBadgeCount(count, withCompletionHandler: { error in
if let error = error {
print("Failed to set badge count: \(error)")
}
})
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound, .badge])
}
}
Any help on why the notification is not displaying would be greatly appreciated.
Upvotes: 0
Views: 83