Search code examples
androidxamarin.formsforeground-serviceforegroundnotification

How to create a foreground service with notification for Android below Oreo 8.0?


I have created a foreground service using the following code which is in the override method OnStartCommand inside a service class called DemoIntentService.cs.

base.OnStartCommand(intent,flags,startId);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
 Intent notificationIntent = new Intent(this, Java.Lang.Class.FromType(typeof(DemoIntentService)));
            PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, 0);

            Notification.Builder notificationBuilder = new Notification.Builder(this, "Example_Service_Channel")
            .SetSmallIcon(Resource.Drawable.AlertLightFrame)
            .SetContentTitle(Resources.GetString(Resource.String.DialogAlertTitle))
            .SetContentText(Resources.GetString(Resource.String.SelectTextMode))
            .SetContentIntent(pendingIntent);

            Notification notificationAfterBuild = notificationBuilder.Build();

            StartForeground(123, notificationAfterBuild);

            InitializeAlarmManager();
            setAlarm();
}
return StartCommandResult.RedeliverIntent;

Obviously, the code above is only for Android Oreo 8.0 and above, the service works fine and the notification will not be cleared even though I close the app manually. (That's good, that's what I want !). However, when I use the above code to test on Android Nougat 7.1.1, it would not work.

Firstly, I have researched online they said there is no need to create a notification channel for Android below 8.0, so I remove the "Example_Service_Channel" which is the channelID. The app was deployed successfully, but the notification gone when I kill the app. Second thing, when I removed the channelID, Xamarin throw me a warning said "Notification.Builder.Builder(Context) is obsolete : deprecated" and the line has turn yellow. I ignore the error and deploy the app. The service did run as it is visible in the running service inside the developer options. But when I killed the app, the service and notification gone together. Is there any other way to create a foreground notification service that will never end for Android below 8.0? Thanks for any comment and idea.


Solution

  • i write a simple sample,and it works on Android 7.1. i just delete the Notification Channel from Android 8.0

    1.Create a Service MyService.cs :

    [Service(Enabled = true)]
    public class MyService : Service
    {
        private Handler handler;
        private Action runnable;
        private bool isStarted;
        private int DELAY_BETWEEN_LOG_MESSAGES = 5000;
        private int NOTIFICATION_SERVICE_ID = 1001;
        private int NOTIFICATION_AlARM_ID = 1002;
        public override void OnCreate()
        {
            base.OnCreate();
    
            handler = new Handler();
    
            //here is what you want to do always, i just want to push a notification every 5 seconds here
            runnable = new Action(() =>
            {
               if (isStarted)
                {
                    DispatchNotificationThatAlarmIsGenerated("I'm running");
                    handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
                }
            });
        }
    
        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            if (isStarted)
            {
                // service is already started
            }
            else
            {
                DispatchNotificationThatServiceIsRunning();
    
                handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
                isStarted = true;
            }
            return StartCommandResult.Sticky;
        }
    
        public override void OnTaskRemoved(Intent rootIntent)
        {
            //base.OnTaskRemoved(rootIntent);
        }
    
        public override IBinder OnBind(Intent intent)
        {
            // Return null because this is a pure started service. A hybrid service would return a binder that would
            // allow access to the GetFormattedStamp() method.
            return null;
        }
    
        public override void OnDestroy()
        {
            // Stop the handler.
            handler.RemoveCallbacks(runnable);
    
            // Remove the notification from the status bar.
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Cancel(NOTIFICATION_SERVICE_ID);
    
            isStarted = false;
            base.OnDestroy();
        }
    
    
    
        //start a foreground notification to keep alive 
        private void DispatchNotificationThatServiceIsRunning()
        {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                   .SetDefaults((int)NotificationDefaults.All)
                   .SetSmallIcon(Resource.Drawable.Icon)
                   .SetVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
                   .SetSound(null)
                   .SetPriority(NotificationCompat.PriorityDefault)
                   .SetAutoCancel(false)
                   .SetContentTitle("Mobile")
                   .SetContentText("My service started")
                   .SetOngoing(true);
    
            NotificationManagerCompat notificationManager = NotificationManagerCompat.From(this);
            StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
        }
    
        //every 5 seconds push a notificaition
        private void DispatchNotificationThatAlarmIsGenerated(string message)
        {
            var intent = new Intent(this, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.ClearTop);
            var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
    
            Notification.Builder notificationBuilder = new Notification.Builder(this)
                .SetSmallIcon(Resource.Drawable.Icon)
                .SetContentTitle("Alarm")
                .SetContentText(message)
                .SetAutoCancel(true)
                .SetContentIntent(pendingIntent);
    
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Notify(NOTIFICATION_AlARM_ID, notificationBuilder.Build());
        }
    }
    

    2.in your activity :

    protected override void OnResume()
      {
          base.OnResume();
          StartMyRequestService();
      }
    public void StartMyRequestService()
      {
          var serviceToStart = new Intent(this, typeof(MyService));
          StartService(serviceToStart);
      }