How to start a background service in ios forever for data synchronization

Hi, I am developing an application that requires a synchronization operation (sending and receiving data) on a web server.

The user can submit forms offline (i.e. store data on a local db on the device). And whenever a network is available, the background service should send this data to the web server.

The background service detail requirement is similar to:

  • The background service will first check if the network is available or not.
  • If the network is available, it will collect the data store in local db (SQLite) on the device
  • It sends data to the server
  • request any new data from the server, and if available, get this data and update the local database on the device.

I am new to iOS and xamarin / monotouch and would like to know how to do this?

I know about various background modes in iOS, such as background selection, nsurlsession, background transfer, etc.

I am trying to implement Background Fetch, which, in my opinion, is suitable for my situation. but he works on his own time.

I would also like to know that if a user killed my application, then also background fetch is called and still starts my application?

the code is similar to this in my appdelegate -> PerformFetch method:

if(networkService.IsNetworkAvailable()) { if(this.syncDataService.DownloadNewDataFromServer()) { Console.WriteLine("Data downloaded successfully from server.."); } if(this.syncDataService.UploadDataToServer()) { Console.WriteLine("Data submitted successfully to server..."); } completionHandler(UIBackgroundFetchResult.NewData); } else { completionHandler(UIBackgroundFetchResult.NoData); } 

Update: Finally, I implemented it this way (hope this can be useful for someone):

 public class LocationUpdatedEventArgs : EventArgs { private CLLocation location; public LocationUpdatedEventArgs(CLLocation location) { this.location = location; } public CLLocation Location { get { return this.location; } } } public class LocationManager { private static DateTime lastServiceRun; private CLLocationManager locMgr; public LocationManager() { this.locMgr = new CLLocationManager(); this.LocationUpdated += this.PrintLocation; this.locMgr.Failed += (object sender, NSErrorEventArgs e) => { Console.WriteLine("didFailWithError " + e.Error); Console.WriteLine("didFailWithError coe " + e.Error.Code); }; } public event EventHandler<LocationUpdatedEventArgs> LocationUpdated = delegate { }; public static TimeSpan TimeDiff { get; set; } public CLLocationManager LocMgr { get { return this.locMgr; } } public void StartLocationUpdates() { if (CLLocationManager.LocationServicesEnabled) { // sets the accuracy that we want in meters this.LocMgr.DesiredAccuracy = 1; //// Location updates are handled differently pre-iOS 6. If we want to support older versions of iOS, //// we want to do perform this check and let our LocationManager know how to handle location updates. if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0)) { this.LocMgr.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) => { //// fire our custom Location Updated event this.LocationUpdated(this, new LocationUpdatedEventArgs(e.Locations[e.Locations.Length - 1])); }; } else { //// this won't be called on iOS 6 (deprecated). We will get a warning here when we build. this.LocMgr.UpdatedLocation += (object sender, CLLocationUpdatedEventArgs e) => { this.LocationUpdated(this, new LocationUpdatedEventArgs(e.NewLocation)); }; } //// Start our location updates this.LocMgr.StartUpdatingLocation(); lastServiceRun = DateTime.Now; // Get some output from our manager in case of failure this.LocMgr.Failed += (object sender, NSErrorEventArgs e) => { Console.WriteLine(e.Error); }; } else { //// Let the user know that they need to enable LocationServices Console.WriteLine("Location services not enabled, please enable this in your Settings"); } } /// <summary> /// The stop updating location. /// </summary> public void StopUpdatingLocation() { this.locMgr.StopUpdatingLocation(); } /// <summary> /// The print location. (This will keep going in the background) /// </summary> /// <param name="sender"> The sender. </param> /// <param name="e"> Location updated event argument </param> public void PrintLocation(object sender, LocationUpdatedEventArgs e) { CLLocation location = e.Location; Console.WriteLine("Longitude: " + location.Coordinate.Longitude); Console.WriteLine("Latitude: " + location.Coordinate.Latitude); var diff = DateTime.Now - lastServiceRun; TimeDiff = diff; if (TimeDiff.Minutes == 2) { // RunInBackground() is my method which call the service to upload/download data from server if (this.RunInBackground()) { lastServiceRun = DateTime.Now; } } } } 
+6
source share
4 answers

The timer never runs in the background, and you cannot add another thread to this method. DidEnterBackground used to perform unfinished tasks. This usually lasts about 30 seconds - 1 minute.

In this method, you can add a loop or add a long-term task.

+2
source

In your delegate to FinishedLaunching, you create a timer that will output the code to the time interval that you set

  public override bool FinishedLaunching(UIApplication app, NSDictionary options) { ... Timer timer = new Timer(5000); //5000 milisecs - 5 secs timer.Elapsed += timer_Elapsed; timer.Start(); ... } private void timer_Elapsed(object sender, ElapsedEventArgs e) { //your code here } 

Also, if a user kills your application, this means that no code even in the background will be called anymore

+2
source

I believe that the solution to your problem is to register your task as a long-term task.

Given that you are using Xamarin, there is also a very good explanation in background tasks using Xamarin here , which is likely to be more relevant for what you want to do.

Also, see application states and multitasking for an explanation of what happens when an application goes into the background: "After returning from the applicationDidEnterBackground method: most applications will soon go to a suspended state. Applications that request specific background tasks (such as playing music) or who request a little extra runtime from the system may continue to work for a while. "

All in all, looking at Apple's developer site is good, since 100% of the iOS APIs are in Xamarin

+2
source

Thought for iOS. A way to do this could be to create a background task scheduler, possibly based on LimitedConcurrencyLevelTaskScheduler ( https://msdn.microsoft.com/en-us/library/ee789351(v=vs.110).aspx ), which will complete your IBackgroundTask tasks . These jobs can be stored in storage and run sequentially. For instance. if you want to download many large files, you want to make them one by one and show the progress or display them in the user interface when they land on your device. Then you queue up any boot task with this scheduler, and you restart it when it is about to die:

 void StartBackgroundTask() { BackgroundTaskId = UIApplication.SharedApplication.BeginBackgroundTask(() => { // Handle expiration: will happen before reaching 600 secs TaskScheduler.Stop(); UIApplication.SharedApplication.EndBackgroundTask(BackgroundTaskId); // Start again StartBackgroundTask(); }); Task.Run(() => { TaskScheduler = new BackgroundTaskScheduler().Start(); }); } 
+2
source

All Articles