Search code examples
c#xamarinxamarin.formsxamarin.androidbackgrounding

Xamarin Forms Background Service For Data Sync Even If App Closes


I Want to create a service which run's in background even if my app closes for data sync of Sqlite and mysql.

i have tried some methods but unable to achieve my goal.

if anyone can give me a sample app which runs a service in the background even if app close

Thanks


Solution

  • If you want to run your background functionality even after your app closes in certain interval, we need to create a foreground service. I am talking about android.

    Firstly create a service class in Android project folder.Here I am creating a service named SqlService.

      [Service]
        class SqlService : Service
        {
            internal static readonly string CHANNEL_ID = "my_notification_channel";
            internal static readonly int NOTIFICATION_ID = 100;
            public override IBinder OnBind(Intent intent)
            {
                return null;
            }
            /*
             * This service will run until stopped explicitly because we are returning sticky
             */
            public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
            {
                Toast.MakeText(this, "Service started", ToastLength.Long).Show();
                StartServiceInForeground();
                return StartCommandResult.Sticky;
            }
            /*
             * When our service is to be destroyed, show a Toast message before the destruction.
             */
            public override void OnDestroy()
            {
                base.OnDestroy();
                Toast.MakeText(this, "Syncing stopped", ToastLength.Long).Show();
            }
    
            void StartServiceInForeground()
            {
    
                if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
                {
                    var intent = new Intent(this, typeof(MainActivity));
    
                    var channel = new NotificationChannel(CHANNEL_ID, "Service Channel", NotificationImportance.High)
                    {
                        Description = "Foreground Service Channel"
                    };
    
                    var notificationManager = (NotificationManager)GetSystemService(NotificationService);
                    notificationManager.CreateNotificationChannel(channel);
                    var pendingIntent = PendingIntent.GetActivity(this, MainActivity.NOTIFICATION_ID, intent, PendingIntentFlags.Immutable);
                    var notification = new Notification.Builder(this, CHANNEL_ID)
                    .SetContentTitle("My Sql App")
                    .SetContentText("Sql Sync is on")
                    .SetContentIntent(pendingIntent)
                    .SetSmallIcon(Resource.Drawable.sr_notification)                
                    .SetOngoing(true)
                    .Build();
                     StartForeground(NOTIFICATION_ID, notification);
                }
    
    
    
                Device.StartTimer(TimeSpan.FromSeconds(300),  () =>
                {
    
                    try
                    {
    
                      //.. Do your sql syncing here 
    
                    }
    
                    catch (Exception ex)
                    {
    
                    }
                    return true;
                });
            }
    
        }
    

    In your MainActivity, you can start the service by using messeging center call from shared project.We also need to create a Notification channel.

    Add this in your MainActivity

     public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {       
            internal static readonly string CHANNEL_ID = "my_notification_channel";
            internal static readonly int NOTIFICATION_ID = 100;
    
           protected override void OnCreate(Bundle savedInstanceState)
            {       
                base.OnCreate(savedInstanceState);         
                Xamarin.Essentials.Platform.Init(this, savedInstanceState);
                global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
                LoadApplication(new App());
                CreateNotificationChannel();
                loadservice();      
            }
    
    
    
    
                void CreateNotificationChannel()
            {
                if (Build.VERSION.SdkInt < BuildVersionCodes.O)
                {
                    // Notification channels are new in API 26 (and not a part of the
                    // support library). There is no need to create a notification 
                    // channel on older versions of Android.
                    return;
                }
    
                var channel = new NotificationChannel(CHANNEL_ID, "FCM Notifications", NotificationImportance.Default)
                {
                    Description = "Firebase Cloud Messages appear in this channel",
                };
                channel.EnableVibration(true);
                channel.EnableLights(true);
    
                var notificationManager = (NotificationManager)GetSystemService(NotificationService);
                notificationManager.CreateNotificationChannel(channel);
            }
    
    
                private void loadservice()
            {
    
                MessagingCenter.Subscribe<Object>(this, "StartLongRunningTaskMessage", (sender) => {
                    Intent myIntent = new Intent(this, typeof(LocationService));
                    this.StartService(myIntent);
                });
    
                MessagingCenter.Subscribe<Object>(this, "StopLongRunningTaskMessage", (sender) => {
                    Intent myIntent = new Intent(this, typeof(LocationService));
                    this.StopService(myIntent);
                });
            }
    }
    

    Now you can Start the service from your shared Project like, Lets say on a Button click.

      private async void Sync_Clicked(object sender, EventArgs e)
        {
         MessagingCenter.Send<Object>(new Object(), "StartLongRunningTaskMessage");     
        }
    

    Also we can stop the service on another button click like:

      private async void Sync_Clicked(object sender, EventArgs e)
            {
             MessagingCenter.Send<Object>(new Object(), "StopLongRunningTaskMessage");      
            }
    

    Revert back if you have any doubts.