Keeping your .NET MAUI background tasks alive when the user force quits the app

Keeping your .NET MAUI background tasks alive when the user force quits the app

11 January 2026

Buy Me A Coffee

Hello! Today we will talk about the "final boss" of mobile development: Keeping your .NET MAUI background tasks alive when the user force-quits the app.

If you’ve ever built a sync engine or a monitoring tool, you know the pain. On Android, we have Foreground Services that can run almost indefinitely. But on iOS, the moment a user swipes your app away in the app switcher, the operating system marks it as "user-terminated" and effectively kills every timer, thread, and CancellationToken you have.

Is it possible to "resurrect" a killed app? Let’s look at the only reliable way to do it in 2026.


The Reality Check: iOS vs. Android

  • Android: Uses WorkManager. If the app is killed, the system will eventually restart your worker based on the constraints (e.g., "Must be charging").

  • iOS: Uses BGTaskScheduler. Crucially, if the user force-quits the app, scheduled background tasks will NOT run. Apple assumes that if the user swiped the app away, they want it dead.

The Secret Weapon: Silent Push Notifications

The only way to wake a "dead" (terminated) app on iOS without user interaction is a Silent Push Notification (Remote Notification). When your server sends a push with the content-available: 1 flag and no alert/sound, iOS wakes your app in the background for about 30 seconds.

1. Configuring the Payload

Your backend must send a JSON payload like this to APNs:

2. Handling the Resurrection in MAUI

In your Platforms/iOS/AppDelegate.cs, you need to override the DidReceiveRemoteNotification method. This is where your app "comes back to life."

The "Resurrection" Pattern: State Restoration

When an app is woken up by a silent push, it doesn't go through the full UI lifecycle. It calls FinishedLaunching but won't create the Window.

The Trap: Many developers put their initialization logic (database setup, API clients) inside the App.xaml.cs constructor or OnStart. In a resurrection scenario, those might not fire correctly.

The Fix: Use a Lazy Initialization Strategy or a ServiceRegistration pattern in MauiProgram.cs that ensures your background services are ready even if the UI hasn't loaded.

Best Practices for 2026

  1. Don't Abuse it: Apple throttles silent pushes. If you send 50 per hour, iOS will stop waking your app. Aim for no more than 2-3 "resurrections" per hour.

  2. The 30-Second Rule: You have exactly 30 seconds. If you don't call the completionHandler, iOS will kill the process and may penalize your app’s future background time.

  3. Combine with BGTaskScheduler: Use the Silent Push to start a task and then use BGTaskScheduler to schedule the next follow-up.

Summary

While you can't prevent a user from killing your app, you can use Silent Push Notifications as a heartbeat to wake it back up. It’s the difference between an app that stays "stale" until the next manual launch and one that always feels up-to-date.

Have you managed to keep your MAUI app alive on iOS? What’s your record for the longest background uptime? Let's discuss!

Buy Me A Coffee

Related:

Creating beautiful image effects using .NET MAUI

The article describes how to create a blur image effect using .NET MAUI behaviors.

Create custom animations using .NET MAUI CommunityToolkit

This article describes how to leverage .NET MAUI CommunityToolkit BaseAnimation and AnimationBehavior to create and apply animation.

An unhandled error has occurred. Reload

🗙