I’m attempting to create a background job to ship numerous notifications at numerous factors within the day, and every of them require a community to examine if the notification must be despatched. I’ve examined the API, and I do know it really works. However when I attempt to add my app to my telephone, nothing occurs (I do know as a result of my API logs by no means present any requests, and I by no means get notifications after I ought to). I adopted this video and browse this documentation, however for some cause, the duty by no means appears to schedule/hearth.
Right here is the associated code:
Community name:
func checkValue(worth: String, hours: Int) async -> Bool {
// Construct url
var urlString = MY_URL + "/Notification"
urlString += "?worth="+worth+"&hours="+String(hours)
guard let url = URL(string: urlString) else {
print("Error: One thing flawed with url.")
return false
}
// construct full request
let urlRequest: URLRequest = {
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10)
request.allHTTPHeaderFields = [
"Token": API_KEY
]
return request
}()
// make request
let config = URLSessionConfiguration.background(withIdentifier: SHOULD_SEND)
config.sessionSendsLaunchEvents = true
let session = URLSession(configuration: config)
// let (knowledge, response) = strive await session.knowledge(for: urlRequest)
let (knowledge, response) = await withTaskCancellationHandler {
strive! await session.knowledge(for: urlRequest)
} onCancel: {
let job = session.downloadTask(with: urlRequest)
job.resume()
}
// guarantee success
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
// deal with if not 200
print("Notification response not 200")
return false
}
//assign worth
return strive! JSONDecoder().decode(Bool.self, from: knowledge)
}
Background Job associated code:
struct NotificationConfig: Equatable {
var id: String
var sort: NotificationType // only a string
var instances: [Int]
var hours: Int
var title: String
var physique: String
}
var notifications: [NotificationConfig] = [ // desired notifications ]
var physique: some Scene {
WindowGroup {
LandingView()
}.backgroundTask(.appRefresh(SCHEDULE_DAILY_NOTIFICATIONS)) {
let nextHour = scheduleAppRefresh()
if nextHour != -1 {
let instances = buildMap()
for notif in instances[nextHour] ?? [] {
let examine = makeCheck(notification: notif)
if await examine() {
self.sendNotification(notif: notif)
}
}
}
} .backgroundTask(.appRefresh("shouldSend")) {
let nextHour = scheduleAppRefresh()
if nextHour != -1 {
let instances = buildMap()
for notif in instances[nextHour] ?? [] {
let examine = makeCheck(notification: notif)
if await examine() {
self.sendNotification(notif: notif)
}
}
}
}
}
func scheduleAppRefresh() -> Int {
let nextHour = getNextNotifIndex()
if nextHour == -1 {
print("OOPS")
}
let calendar = Calendar.present
let timeZone = TimeZone.present
var dateComponents = calendar.dateComponents(in: timeZone, from: Date())
dateComponents.hour = nextHour
dateComponents.minute = 0
dateComponents.second = 0
guard var desiredTime = calendar.date(from: dateComponents) else {
return -1
}
// if not in future, add a day
if desiredTime.examine(Date()) == .orderedAscending {
desiredTime = calendar.date(byAdding: .day, worth: 1, to: desiredTime)!
}
let request = BGAppRefreshTaskRequest(identifier: SCHEDULE_DAILY_NOTIFICATIONS)
request.earliestBeginDate = calendar.date(byAdding: .minute, worth: -1, to: desiredTime)!
do {
strive BGTaskScheduler.shared.submit(request)
} catch {
print("Couldn't schedule app refresh: (error)")
}
return nextHour
}
func buildMap() -> [Int: [NotificationConfig]] {
var instances = [Int: [NotificationConfig]]()
for notif in self.notifications {
for time in notif.instances {
if instances[time] != nil {
instances[time]!.append(notif)
} else {
instances[time] = [notif]
}
}
}
return instances
}
func getNextNotifIndex() -> Int {
let timers = buildMap()
let now = Date()
let calendar = Calendar.present
let timeZone = TimeZone.present
for hour in timers.keys.sorted() {
var dateComponents = calendar.dateComponents(in: timeZone, from: now)
dateComponents.hour = hour
guard let thisTime = calendar.date(from: dateComponents) else {
proceed
}
if thisTime.examine(now) == .orderedSame || thisTime.examine(now) == .orderedDescending {
return hour
}
}
return -1
}
func makeCheck(notification: NotificationConfig) -> () async -> Bool {
return {
return checkValue(worth: notification.sort, hours: notification.hours, meal: meal)
}
}
// Perform to ship a notification for a particular hour
func sendNotification(notif: NotificationConfig) {
UNUserNotificationCenter.present().requestAuthorization(choices: [.alert, .sound, .badge]) { granted, error in
if granted {
print("Notification authorization granted")
let content material = UNMutableNotificationContent()
content material.title = notif.title
content material.physique = notif.physique
content material.sound = UNNotificationSound.default
let set off = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let identifier = "notification_(notif.instances[0])_(notif.id)"
let request = UNNotificationRequest(identifier: identifier, content material: content material, set off: set off)
UNUserNotificationCenter.present().add(request) { error in
if let error = error {
print("Error scheduling notification for hour: (error)")
} else {
print("Notification scheduled efficiently")
}
}
}
}
}
Sorry for the code dump, however I do not know why it isn’t working. I adopted the steps within the documentation, and arrange my app settings (together with the Permitted background job scheduler identifiers in Information.plist), nevertheless it by no means even reaches the within of the .backgroundTask Scene Modifier (utilizing debugger with breakpoints, by no means cease anyplace within the background job operate. A number of the opposite helper features have been examined and may work, however I included them simply in case. What might be inflicting this to occur, and what are steps I may take to debug background duties? That is my first time utilizing them, and all assist could be appreciated.
Are there any additional steps to arrange background duties than the developer docs that must be taken? Maybe on the system, not in XCode on the mission?