How to Exit a .NET MAUI App

Programming .NET MAUI

Have you ever wondered what the correct way to exit an .NET MAUI app on different devices looks like?

Application.Current.Quit wont work on iOS or Android - and that has a simple reason: by design, the philosophy on mobile devices is that apps simply should not quiet themselves. Because a coldstart of an app takes a little longer than just re-activating it.

But when you have a professional looking navigation menu, an "Exit" item would look even more professional. What a dilemma. If you don't care about the "mobile apps should not quite themselves" philosophy then here's the way to do so.

First we need an interface like

    public interface IExitService
    {
        void Exit();
  }

Now we need three different implementations. One for Android, one for iOS and another one for the Desktop version. Let's start with the Android implementation first:

#if ANDROID
    public class AndroidExitService : IExitService
    {
        public void Exit()
        {
            Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
        }
    }
#endif

For iOS we do

#if IOS
  public class IOSExitService : IExitService
    {
        public void Exit()
        {
            UIApplication.SharedApplication.PerformSelector(
new ObjCRuntime.Selector("terminateWithSuccess"),
UIApplication.SharedApplication);
        }
    }
#endif

And here's the implementation for the desktop

#if WINDOWS || MACCATALYST
    public class DesktopExitService : IExitService
    {
        public void Exit()
        {
            Application.Current!.Quit();
        }
    }
#endif

Now we need to register those implementations with the .NET DI container, done in MauiProgram.cs

        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()

            // ....

#if WINDOWS || MACCATALYST
        builder.Services.AddSingleton<IExitService, DesktopExitService>();
#elif ANDROID
        builder.Services.AddSingleton<IExitService, AndroidExitService>();
#elif IOS
      builder.Services.AddSingleton<IExitService, IOSExitService>();

            // ...

            return builder.Build();
        }

Now we can inject the ExitService to our ViewModel and simply call Exit where needed

 public partial class DashboardViewModel : ObservableRecipient
  {
        private readonly ModalErrorHandler _errorHandler;
private readonly IExitService _exitService;

        public DashboardViewModel(ModalErrorHandler errorHandler, IExitService exitService)
        {
            _errorHandler = errorHandler;
            _exitService = exitService;

          // further initializations as needed
        }
        
        // ... other ViewModel implementations
        
        [RelayCommand]
        public void OnExit()
        {
          _exitService.Exit();
        }
    }