How do I cause a timer to fire while the app is in the background?

When I write code for a timer like below, the timer doesn't fire if the device is locked. How do I cause the code in the timer closure to run when the app is in the background? Are there any other ways to cause specific code to run at a certain time when the app is in the background?


    func setTimer(alarm: UTIAlarm) {
        
        let timer = Timer(fire: alarm.date!, interval: 0, repeats: false) {
            
            (timer: Timer) in
            
            print("timer fire \(self.dateFormatter.string(from: alarm.date!))")
            
            do {
                try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
            } catch {
                print("Failed to setActive AVAudioSession from timer closure.")
                print(error.localizedDescription)
            }
            
            let predicate = MPMediaPropertyPredicate(value: alarm.mediaItem!.title, forProperty: MPMediaItemPropertyTitle)
            let query = MPMediaQuery()
            query.addFilterPredicate(predicate)
            
            self.playerController!.setQueue(with: query)
            self.playerController!.play()

        }

        runLoop.add(timer, forMode: .default)

        timers.append(timer)
        
    }
Answered by PBK in 341449022

>I am not aware of any iOS API that will allow you to run code on a fixed schedule from the background.


This OP often posts similar questions on multiple boards. In one of those similar messages I responded that you could do this through remote notifications generated by your own server or through CloudKit.


see:

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_updates_to_your_app_silently?language=objc


https://developer.apple.com/documentation/usernotifications/handling_notifications_and_notification-related_actions?language=objc


and also:

Use a CKQuerySubscription with a query that was satisfied by any file that was modifed in a particular CloudKit container after a particular time - e.g. 25 minutes from now, repeatedly. And then you could run, anywhere on the planet, an app that modifed a dummy file in that same CloudKit Zone every minute. That would trigger a remote notification associated with the subscription in 25 minutes. The remote notification would reset the subscription.

Seen this previous discussion?


https://forums.developer.apple.com/thread/75468

> Are there any other ways to cause specific code to run at a certain time when the app is in the background?



No. That cannot be done on iOS. This has been discussed many many times here on these forums.

I have an app installed on my iPhone that is able to set an "alarm" that plays a sound or music from the iPhone device's music library at a specified time set by the "alarm" while the app is in the background and even when the device is locked. At the same time the sound or music plays, a notification appears on the lock screen, but I think it is independent of the sound or music playing. They just happen to occur at the same time. The sound or music is longer than 30 seconds, so it's not from the sound property of a UNNotificationContent object, which limits the sound to 30 seconds long. Any idea how that app does that? I tried running the audio file from a notificaion extension, but there is no place to run the code when the notification first appears. There are only places to run code when the user interacts with the notification.

How old is that app? It’s possible it made it through review at a time when guidelines were different. It’s also possible it’s doing something shady, accessing a private API or abusing background modes (audio, voip, location etc.) to keep the app alive when it shouldn’t be. Bottom line, I don’t know how that other app works, but I am not aware of any iOS API that will allow you to run code on a fixed schedule from the background.

Accepted Answer

>I am not aware of any iOS API that will allow you to run code on a fixed schedule from the background.


This OP often posts similar questions on multiple boards. In one of those similar messages I responded that you could do this through remote notifications generated by your own server or through CloudKit.


see:

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_updates_to_your_app_silently?language=objc


https://developer.apple.com/documentation/usernotifications/handling_notifications_and_notification-related_actions?language=objc


and also:

Use a CKQuerySubscription with a query that was satisfied by any file that was modifed in a particular CloudKit container after a particular time - e.g. 25 minutes from now, repeatedly. And then you could run, anywhere on the planet, an app that modifed a dummy file in that same CloudKit Zone every minute. That would trigger a remote notification associated with the subscription in 25 minutes. The remote notification would reset the subscription.

It is absolutely useless to use push notifications as a timer. When I'm in bed, my cell phone is under the bed and sometimes has no connection. How does Apple envision it? How can I build a great alarm clock if my app only rings when there is good internet connection?

With Android that's no problem at all, I can set an alarm in the time manager. As usual, it is not 100% accurate because the system may have a slightly different loop, but it is always available!

In addition, it is absolutely unclear to me how this is supposed to work in airplane mode?

How do I cause a timer to fire while the app is in the background?
 
 
Q