I’m making an attempt to create a background activity to ship varied notifications at varied factors within the day, and every of them require a community to test if the notification needs to be despatched. I’ve examined the API, and I do know it really works. However when I attempt to add my app to my cellphone, 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 purpose, the duty by no means appears to schedule/fireplace.
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 mistaken 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 (information, response) = attempt await session.information(for: urlRequest)
let (information, response) = await withTaskCancellationHandler {
attempt! await session.information(for: urlRequest)
} onCancel: {
let activity = session.downloadTask(with: urlRequest)
activity.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 attempt! JSONDecoder().decode(Bool.self, from: information)
}
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 test = makeCheck(notification: notif)
if await test() {
self.sendNotification(notif: notif)
}
}
}
} .backgroundTask(.appRefresh("shouldSend")) {
let nextHour = scheduleAppRefresh()
if nextHour != -1 {
let instances = buildMap()
for notif in instances[nextHour] ?? [] {
let test = makeCheck(notification: notif)
if await test() {
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 {
attempt 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)
}
}
// Operate to ship a notification for a selected 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 don’t know why it is not working. I adopted the steps within the documentation, and arrange my app settings (together with the Permitted background activity 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 wherever within the background activity perform. A variety of the opposite helper capabilities have been examined and will 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 can be appreciated.
Are there any additional steps to arrange background duties than the developer docs that should be taken? Maybe on the machine, not in XCode on the undertaking?