How to keep meditation timer running if app is in background or phone is locked?

I've just finished making a meditation app for iphone using swiftui which includes a timer.

The only problem is the timer stops when the app is in the background or the phone is locked.

The user can select between 2 and 60 minutes on the timer and play, pause, reset the timer. When seconds remaining equals zero the timer ends and a meditation bell sound plays to signal the end of the meditation.

Currently I use the default timer on the iphone when I meditate in the Clock app. If I set this timer for 20 minutes and lock the phone, at the end of the 20 minutes the timer will go off and notify me with whatever sound I selected in "When Timer Ends".

If the default Clock app on the iphone has this basic functionality, why is it so hard to have the same functionality in the meditation app I'm making?

Wouldn't the safest/easiest way to have the timer run in the background or when the phone is locked be the same method the default Clock app uses?

While meditating, we don't want to have our phone giving off light by having to be unlocked so the timer can continue running.

We want to be able to lock the phone so it's not giving off light and be reminded when the time ends or if we unlock the phone to check how much time is remaining.

Any thoughts would be appreciated.

Have checked stackoverflow and other places but the fixes and work around methods don't directly apply to the use case.

Accepted Reply

The best way to go about this is to schedule a local notification to trigger whenever the timer is set to expire.

When your application is about to move into the background, calculate a timestamp based on the current time and time left, schedule the notification, and then stop all work in your application related to the countdown (like UI loops or any other in-app work). If the user leaves the app or locks the phone, they will receive a notification at that time to bring them back into the app. When your app moves back into the foreground, update your your based on the current time: if any of their timers expired, show the UI as completed; if not, start a new loop to manage the countdown UI from the current point with the time left.

Unfortunately iOS will not give you enough time running in the background to keep a timer active. You get a few moments to do clean up work (like what I mention above) but nothing more — even attempting to request more time from the system will not give you the length you are looking for… and if you keep doing work too long in the background, iOS will terminate just your application. Ideally, unless you are updating the UI on screen (like a visual countdown), you shouldn’t be running an ongoing task like this— it’s better to schedule these events out ahead of time: there’s much less work for the system to do and much less for you to manage this way.

Using notifications you can get several customizations to help integrate with system features like Wind Down and some even more interesting ones in iOS 15 — you can’t get something exactly like clock which is a part of the system, but you CAN get something good!

  • Thank you for the response Jimmy.

    The question I had with this approach is what to do if they open the app again before the timer has completed. But I think you've addressed that here:

    "When your app moves back into the foreground, update your your based on the current time: if any of their timers expired, show the UI as completed; if not, start a new loop to manage the countdown UI from the current point with the time left."

    Will just have to try this way for now & will keep an eye out for the updates for iOS15.

    Thanks

Add a Comment

Replies

The best way to go about this is to schedule a local notification to trigger whenever the timer is set to expire.

When your application is about to move into the background, calculate a timestamp based on the current time and time left, schedule the notification, and then stop all work in your application related to the countdown (like UI loops or any other in-app work). If the user leaves the app or locks the phone, they will receive a notification at that time to bring them back into the app. When your app moves back into the foreground, update your your based on the current time: if any of their timers expired, show the UI as completed; if not, start a new loop to manage the countdown UI from the current point with the time left.

Unfortunately iOS will not give you enough time running in the background to keep a timer active. You get a few moments to do clean up work (like what I mention above) but nothing more — even attempting to request more time from the system will not give you the length you are looking for… and if you keep doing work too long in the background, iOS will terminate just your application. Ideally, unless you are updating the UI on screen (like a visual countdown), you shouldn’t be running an ongoing task like this— it’s better to schedule these events out ahead of time: there’s much less work for the system to do and much less for you to manage this way.

Using notifications you can get several customizations to help integrate with system features like Wind Down and some even more interesting ones in iOS 15 — you can’t get something exactly like clock which is a part of the system, but you CAN get something good!

  • Thank you for the response Jimmy.

    The question I had with this approach is what to do if they open the app again before the timer has completed. But I think you've addressed that here:

    "When your app moves back into the foreground, update your your based on the current time: if any of their timers expired, show the UI as completed; if not, start a new loop to manage the countdown UI from the current point with the time left."

    Will just have to try this way for now & will keep an eye out for the updates for iOS15.

    Thanks

Add a Comment