Skip to content

[Android] Foreground Service

Elvin Thudugala edited this page Mar 29, 2026 · 1 revision

Android Foreground Service Notifications

A foreground service keeps your app alive while background work is running and is required to show a persistent notification that the user can always see. This is the correct approach for ongoing work such as file uploads, music playback, location tracking, or long-running sync operations.

For one-shot notifications (including scheduled ones) you do not need a foreground service — use LocalNotificationCenter.Current.Show() instead.


How It Works

  1. Your app calls StartForegroundServiceAsync with a description of the work and a notification to display.
  2. The plugin starts an Android Service, calls startForeground(), and posts the notification immediately.
  3. Android keeps the service process alive until you call StopForegroundServiceAsync.
  4. The notification is removed and the service process ends on stop.

Manifest Setup

Three additions are required in Platforms/Android/AndroidManifest.xml:

<!-- Required for all foreground services -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- Required on Android 14+ for the specific service type you use.
     Replace "short_service" with the permission matching your AndroidForegroundServiceType. -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SHORT_SERVICE" />

<!-- Declare the service. Use tools:node="merge" so the value merges with the
     plugin's own manifest entry rather than creating a duplicate. -->
<service
    android:name="plugin.LocalNotification.NotificationForegroundService"
    android:foregroundServiceType="shortService"
    android:exported="false"
    tools:node="merge" />

Make sure the tools namespace is declared on the root <manifest> element:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">

Permission and manifest value per service type

AndroidForegroundServiceType android:foregroundServiceType Extra <uses-permission> (API 34+)
ShortService shortService FOREGROUND_SERVICE_SHORT_SERVICE
DataSync dataSync FOREGROUND_SERVICE_DATA_SYNC
MediaPlayback mediaPlayback FOREGROUND_SERVICE_MEDIA_PLAYBACK
PhoneCall phoneCall FOREGROUND_SERVICE_PHONE_CALL
Location location FOREGROUND_SERVICE_LOCATION
ConnectedDevice connectedDevice FOREGROUND_SERVICE_CONNECTED_DEVICE
Camera camera FOREGROUND_SERVICE_CAMERA
Microphone microphone FOREGROUND_SERVICE_MICROPHONE
Health health FOREGROUND_SERVICE_HEALTH
RemoteMessaging remoteMessaging FOREGROUND_SERVICE_REMOTE_MESSAGING
MediaProjection mediaProjection FOREGROUND_SERVICE_MEDIA_PROJECTION
SpecialUse specialUse FOREGROUND_SERVICE_SPECIAL_USE

Multiple types can be combined (bitwise OR):

android:foregroundServiceType="dataSync|location"
ForegroundServiceType = AndroidForegroundServiceType.DataSync | AndroidForegroundServiceType.Location

Usage

Access the Android-specific service by casting LocalNotificationCenter.Current to IAndroidNotificationService:

using Plugin.LocalNotification;
using Plugin.LocalNotification.Core.Models;
using Plugin.LocalNotification.Core.Models.AndroidOption;

#if ANDROID
var androidService = LocalNotificationCenter.Current as IAndroidNotificationService;
if (androidService is not null)
{
    await androidService.StartForegroundServiceAsync(new AndroidForegroundServiceRequest
    {
        ForegroundServiceType = AndroidForegroundServiceType.ShortService,
        Notification = new NotificationRequest
        {
            NotificationId = 1001,
            Title = "Syncing data…",
            Description = "Your data is being synchronised in the background.",
        }
    });
}
#endif

Stopping the service

#if ANDROID
var androidService = LocalNotificationCenter.Current as IAndroidNotificationService;
await androidService?.StopForegroundServiceAsync();
#endif

Using LocalNotificationCenter.AndroidService

If you are already on Android and want a cleaner call site, use the AndroidService accessor:

#if ANDROID
await LocalNotificationCenter.AndroidService.StartForegroundServiceAsync(new AndroidForegroundServiceRequest
{
    ForegroundServiceType = AndroidForegroundServiceType.DataSync,
    Notification = new NotificationRequest
    {
        NotificationId = 2001,
        Title = "Uploading files",
        Description = "3 of 10 files uploaded",
        Android = { ChannelId = "upload_channel" }
    }
});

// … do upload work …

await LocalNotificationCenter.AndroidService.StopForegroundServiceAsync();
#endif

Using a Custom Notification Channel

The notification shown by the foreground service uses AndroidOptions.DefaultChannelId unless you specify a different channel. Create a dedicated channel in MauiProgram.cs for the best user experience:

builder.UseLocalNotification(config =>
{
    config.AddAndroid(android =>
    {
        android.AddChannel(new AndroidNotificationChannelRequest
        {
            Id = "background_work",
            Name = "Background Work",
            Description = "Shown while background tasks are running",
            Importance = AndroidImportance.Low,   // Low importance keeps it quiet
            EnableVibration = false,
            EnableSound = false
        });
    });
});

Then reference the channel in the notification request:

Notification = new NotificationRequest
{
    NotificationId = 3001,
    Title = "Processing…",
    Android = { ChannelId = "background_work" }
}

AndroidForegroundServiceType Reference

Value Bit Description Min API
None 0 No type constraint. All
DataSync 1 Network upload or download. 29
MediaPlayback 2 Audio playback or recording. 29
PhoneCall 4 Phone or VoIP call. 29
Location 8 Device location tracking. 29
ConnectedDevice 16 Connection to a Bluetooth/NFC/USB device. 29
MediaProjection 32 Screen capture or media projection. 29
Camera 64 Camera stream processing. 29
Microphone 128 Microphone access. 30
Health 256 Health-related task. 34
RemoteMessaging 512 Remote messaging. 34
ShortService 2048 Brief user-triggered task (must finish within a few minutes). 34
SpecialUse Special use approved by Google. 34

On Android 13 (API 33) and earlier, the type value passed to startForeground is ignored by the OS. The plugin still passes it for forward compatibility.


AndroidForegroundServiceRequest Properties

Property Type Default Description
ForegroundServiceType AndroidForegroundServiceType ShortService The service type(s) declared in the manifest.
Notification NotificationRequest? null The notification to show. When null, a minimal notification with the app name as title is generated automatically.

Updating the Notification While Running

The service does not provide a direct API to update its notification in place. The typical pattern is to cancel the old notification and re-show a new one using MyNotificationManager.Notify(id, notification) on the same notification identifier:

// Show a plain notification with updated text over the service's persistent notification
await LocalNotificationCenter.Current.Show(new NotificationRequest
{
    NotificationId = 1001,          // same ID used in StartForegroundServiceAsync
    Title = "Syncing data…",
    Description = "8 of 10 items done",
    Android = { Ongoing = true, AutoCancel = false }
});

Limitations

  • ShortService (API 34+): Android enforces a time limit of a few minutes. Use a different type (e.g., DataSync) for long-running operations.
  • Background process restrictions: On Android 12+ the system may delay startForegroundService calls when the app is in the background. Start the service from a foreground context (Activity, system broadcast) where possible.
  • iOS / Windows / MacCatalyst: StartForegroundServiceAsync is only available on Android. Calling it on other platforms is a compile error (access it inside #if ANDROID or via a cast).

Clone this wiki locally