Android Foreground Services
Android foreground services keep your app alive in the background by showing a persistent notification that signals to the user that something is actively running (and potentially consuming battery). Android requires this notification — you cannot perform long-running background work without it.
Several Shiny modules rely on a foreground service to function correctly on Android:
- GPS (
Shiny.Locations) — continuous location tracking - Beacon Monitoring (
Shiny.Beacons) — monitoring beacon regions - HTTP Transfers (
Shiny.Net.Http) — resumable uploads and downloads - BLE Hosting (
Shiny.BluetoothLE.Hosting) — advertising as a peripheral
Shiny manages the foreground service lifecycle for you. You only need to ensure the required manifest entries are in place and — optionally — customize the notification that is shown to the user.
Manifest Requirements
Section titled “Manifest Requirements”The supporting Shiny package for each module automatically contributes the required android.permission.FOREGROUND_SERVICE and module-specific permissions (e.g. FOREGROUND_SERVICE_LOCATION for GPS) into your merged manifest. You must also ensure your app has:
- A valid launcher icon, or a drawable named
notificationin yourResources/drawablefolder. Shiny uses this as the small icon on the persistent notification when you haven’t customized it. - The appropriate runtime permissions requested (e.g.
ACCESS_BACKGROUND_LOCATIONfor GPS) — Shiny’sRequestAccessmethods handle the prompts.
Customizing the Notification
Section titled “Customizing the Notification”Shiny shows a sensible default notification, but in almost all production apps you will want to control the title, text, icon, and tap behavior. You do this by having your delegate also implement Shiny.IAndroidForegroundServiceDelegate:
public interface IAndroidForegroundServiceDelegate{ void Configure(NotificationCompat.Builder builder);}Because this interface lives in the Android-specific Shiny namespace, implement it inside an #if ANDROID block on a partial class so the rest of your delegate stays cross-platform.
Example — GPS Delegate
Section titled “Example — GPS Delegate”using Shiny.Locations;
public partial class MyGpsDelegate : IGpsDelegate{ public Task OnReading(GpsReading reading) { // cross-platform logic return Task.CompletedTask; }}
#if ANDROIDusing AndroidX.Core.App;
public partial class MyGpsDelegate : Shiny.IAndroidForegroundServiceDelegate{ public void Configure(NotificationCompat.Builder builder) { builder .SetContentTitle("MyApp") .SetContentText("Tracking your route") .SetSmallIcon(Resource.Mipmap.youricon) .SetPriority((int)NotificationCompat.PriorityLow) .SetCategory(NotificationCompat.CategoryService); }}#endifThe same pattern applies to every module that uses a foreground service:
| Module | Delegate Interface |
|---|---|
| GPS | Shiny.Locations.IGpsDelegate + Shiny.IAndroidForegroundServiceDelegate |
| Beacon Monitoring | Shiny.Beacons.IBeaconMonitorDelegate + Shiny.IAndroidForegroundServiceDelegate |
| HTTP Transfers | Shiny.Net.Http.IHttpTransferDelegate + Shiny.Net.Http.IAndroidHttpTransferDelegate |