- Expected behavior
- ios
- When the app is minimized and notifications come in every 5 seconds.
- Android
- When the app is minimized and notifications come in every 5 seconds.
- ios
- Actual behavior
- ios
- App minimizes and no notifications come in, opening the app causes notifications to come in every 5 seconds.
- Android
- When the app is minimized and notifications come in every 5 seconds.
//from app.xaml.cs protected override void OnSleep() { void ScheduleNotification() { // Start a timer that runs after 5 seconds. Device.StartTimer(TimeSpan.FromSeconds(5), () => { System.Threading.Tasks.Task.Factory.StartNew( () => { // Do the actual request and wait for it to finish. PerformNotification(); // Switch back to the UI thread to update the UI Device.BeginInvokeOnMainThread(() => { // Update the UI // ... // Now repeat by scheduling a new request ScheduleNotification(); count++; }); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // Don't repeat the timer (we will start a new timer when the request is finished) return false; }); } void PerformNotification() { CrossLocalNotifications.Current.Show("title", "body"+ count.ToString()); } ScheduleNotification(); }
- When the app is minimized and notifications come in every 5 seconds.
- ios
Asked
Active
Viewed 9,017 times
4

Jacob Ernst
- 97
- 3
- 14
-
1iOS does *not* allow unlimited background processing time except for apps with special entilitement, review : https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/backgrounding/ios-backgrounding-techniques/ Also you will need to create an Android foregrounded service (at a min.) as your Android technique will not on later APIs. – SushiHangover Mar 28 '18 at 19:44
-
So I will need to implement platform specific code on ios as well as enable background modes in info.plst and on android my target platform is 8.1, when will this method stop working? – Jacob Ernst Mar 28 '18 at 19:57
-
Android 8.0+ https://developer.android.com/about/versions/oreo/background.html – SushiHangover Mar 28 '18 at 19:58
1 Answers
3
On iOS, apps that don't request to be run in the Background, can not run in the Background for longer than 10 seconds. In order to make some code run in the Background you could implement a DependencyService on iOS and on android. You would put the following code inside that service on iOS:
public async Task RunCodeInBackgroundMode(Func<Task> action, string name = "MyBackgroundTaskName")
{
nint taskId = 0;
var taskEnded = false;
taskId = UIApplication.SharedApplication.BeginBackgroundTask(name, () =>
{
//when time is up and task has not finished, call this method to finish the task to prevent the app from being terminated
Console.WriteLine($"Background task '{name}' got killed");
taskEnded = true;
UIApplication.SharedApplication.EndBackgroundTask(taskId);
});
await Task.Factory.StartNew(async () =>
{
//here we run the actual task
Console.WriteLine($"Background task '{name}' started");
await action();
taskEnded = true;
UIApplication.SharedApplication.EndBackgroundTask(taskId);
Console.WriteLine($"Background task '{name}' finished");
});
await Task.Factory.StartNew(async () =>
{
//Just a method that logs how much time we have remaining. Usually a background task has around 180 seconds to complete.
while (!taskEnded)
{
Console.WriteLine($"Background task '{name}' time remaining: {UIApplication.SharedApplication.BackgroundTimeRemaining}");
await Task.Delay(1000);
}
});
}
On Android you could use the following code:
public async Task RunCodeInBackgroundMode(Func<Task> action, string name = "MyBackgroundTaskName")
{
var powerManager = (PowerManager)Application.Context.GetSystemService(Context.PowerService);
var wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial,
name);
//acquire a partial wakelock. This prevents the phone from going to sleep as long as it is not released.
wakeLock.Acquire();
var taskEnded = false;
await Task.Factory.StartNew(async () =>
{
//here we run the actual code
Console.WriteLine($"Background task '{name}' started");
await action();
Console.WriteLine($"Background task '{name}' finished");
wakeLock.Release();
taskEnded = true;
});
await Task.Factory.StartNew(async () =>
{
//just a method to keep track of how long the task runs
var stopwatch = new Stopwatch();
stopwatch.Start();
while (!taskEnded)
{
Console.WriteLine($"Background '{name}' task with wakelock still running ({stopwatch.Elapsed.TotalSeconds} seconds)");
await Task.Delay(1000);
}
stopwatch.Stop();
});
}
Inside the shared project, you could call those methods in the following way:
var deviceInfoServic = ServiceLocator.Instance.Get<YourService Interface here>();
await deviceInfoServic.RunCodeInBackgroundMode(async () =>
{
//your code here
});

user2074945
- 537
- 2
- 8
- 22
-
-
Sorry, I thought you already have this set up, I think it’s even part of most of the xamarin project templates. Anyway, take a look here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction – user2074945 Mar 29 '18 at 04:10
-
I the link referenced above they use DependencyService.Get in what looks to be where you have ServiceLocator.Instance. Is this correct? – Jacob Ernst Mar 29 '18 at 17:25
-
[App.xaml.cs](https://pastebin.com/kAz3ayZf) The same behavior is observed on ios, it will not run in the background but instead when you resume the app. But on Android, it works even on api level 26 – Jacob Ernst Mar 29 '18 at 20:12
-
hmm, what is logged on iOS for "Background task time remaining:"? Maybe there is an issue with updating the UI from the background (Device.BeginInvokeOnMainThread). Can you try it with a background task, that only logs to console every second? To make sure, the problem is not caused by some other parts of your code. – user2074945 Mar 29 '18 at 20:19
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167839/discussion-between-jacob-ernst-and-user2074945). – Jacob Ernst Mar 29 '18 at 21:43
-
1Discussion synopsis; Make sure //your code here; contains a async method that can be await – Jacob Ernst Mar 29 '18 at 22:40