Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Xamarin foreground service

Trying to create my first Xamarin foreground service but can't find a suitable example. The examples in Microsoft documentation seem to be either incomplete or use depreciated Notification.Builder:

https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/services/foreground-services

https://docs.microsoft.com/en-us/samples/xamarin/monodroid-samples/applicationfundamentals-servicesamples-foregroundservicedemo/

I've found ONE code example that seems to be up to date, but I'm struggling to decipher how it works by looking at the code:

https://docs.microsoft.com/en-us/samples/xamarin/monodroid-samples/android-o-androidplaylocation-locupdfgservice/

Can anyone give me an example of how to create basic foreground service?

like image 728
David Andrew Thorpe Avatar asked Apr 07 '20 12:04

David Andrew Thorpe


1 Answers

I have finally stitched together an answer. Here is an example for anyone who find themselves here:

Create a Dependency Service so you can call your Start/Stop service methods from your shared code.

Make Interface:

public interface IAndroidService
    {
        void StartService();

        void StopService();
    }

Implement a class within your android project which uses the interface. Remember to add assembly reference.

[assembly: Xamarin.Forms.Dependency(typeof(AndroidServiceHelper))]

namespace YourNameSpace.Droid
{
    internal class AndroidServiceHelper : IAndroidService
    {
        private static Context context = global::Android.App.Application.Context;

        public void StartService()
        {
            var intent = new Intent(context, typeof(DataSource));

            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {
                context.StartForegroundService(intent);
            }
            else
            {
                context.StartService(intent);
            }
        }

        public void StopService()
        {
            var intent = new Intent(context, typeof(DataSource));
            context.StopService(intent);
        }
    }
}

Now we do pretty much the same (create interface and implement in class within android project) for creating the notification needed for a Foreground Service:

The interface for creating notifications

public interface INotification
    {
        Notification ReturnNotif();
    }

Create a class inside of the android project that implements INotification so we can create and return a notification object which we need to start a Foreground Service. Remember to add the assembly reference:

[assembly: Xamarin.Forms.Dependency(typeof(NotificationHelper))]

namespace MetroAlarmHandlerMobile.Droid
{
    internal class NotificationHelper : INotification
    {
        private static string foregroundChannelId = "9001";
        private static Context context = global::Android.App.Application.Context;


        public Notification ReturnNotif()
        {
            // Building intent
            var intent = new Intent(context, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.SingleTop);
            intent.PutExtra("Title", "Message");

            var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.UpdateCurrent);

            var notifBuilder = new NotificationCompat.Builder(context, foregroundChannelId)
                .SetContentTitle("Your Title")
                .SetContentText("Main Text Body")
                .SetSmallIcon(Resource.Drawable.MetroIcon)
                .SetOngoing(true)
                .SetContentIntent(pendingIntent);

            // Building channel if API verion is 26 or above
            if (global::Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                NotificationChannel notificationChannel = new NotificationChannel(foregroundChannelId, "Title", NotificationImportance.High);
                notificationChannel.Importance = NotificationImportance.High;
                notificationChannel.EnableLights(true);
                notificationChannel.EnableVibration(true);
                notificationChannel.SetShowBadge(true);
                notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });

                var notifManager = context.GetSystemService(Context.NotificationService) as NotificationManager;
                if (notifManager != null)
                {
                    notifBuilder.SetChannelId(foregroundChannelId);
                    notifManager.CreateNotificationChannel(notificationChannel);
                }
            }

            return notifBuilder.Build();
        }
}

Create a class that inherits and overrides from Service. This is a class created in your shared code and is where we will call the methods that we want to run on the Foreground Service.

public class DataSource : Service
    {

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        public const int ServiceRunningNotifID = 9000;

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            Notification notif = DependencyService.Get<INotification>().ReturnNotif();
            StartForeground(ServiceRunningNotifID, notif);

            _ = DoLongRunningOperationThings();

            return StartCommandResult.Sticky;
        }

        public override void OnDestroy()
        {
            base.OnDestroy();
        }

        public override bool StopService(Intent name)
        {
            return base.StopService(name);
        }


}

You can now start and stop your Foreground Service using Dependency Service anywhere in your shared code using the following code:

Start

DependencyService.Get<IAndroidService>().StartService();

Stop

DependencyService.Get<IAndroidService>().StopService();
like image 91
David Andrew Thorpe Avatar answered Oct 04 '22 22:10

David Andrew Thorpe