A small intro
Really hope that some of you are willing to help me get this issue out of the way before I loose the rest of my hair.
I know that there are hundreds of posts out there regarding this issue but the more I read the more confused I get and no post concludes a final solution that works on all Android versions.
The only thing I can be sure of is that I tried almost every possible solution that I can think of and that I'm still not happy with the result.
What I'm trying to accomplish
I need a background service of some kind running on Android platform (old as well as new (7+)) that can get the device position by GPS and post it to my server. I need to have it run at a specific interval and I do not give a s... about battery optimization and Doze.
Visual Studio 2015 with all the Xamarin addins etc. (On Windows 10)
HTC One M9 running Android 7.0
What I have tried so far
I started of by this example: https://developer.xamarin.com/samples/mobile/BackgroundLocationDemo/.
Download, Build, Deploy with USB cable on my phone. Worked fine.
Then i wrapped it in a BroadcastReceiver and using AlarmManager to schedule the Location updates so it would continue to run even if the app was closed. That also worked fine.
The main project setup is a MainActivity with some start/stop buttons, a BroadcastReceiver and a Location Service (ILocationListener).
Until I updated my phone (from Android 6.0 to 7.0) the AlarmManager worked fine by just initiating on intervals like so
alarmManager.SetRepeating(AlarmType.ElapsedRealtimeWakeup, ElapsedRealtime, interval, pendingIntent);
with interval setup to every about 4 minutes.
But after upgrading the phone to 7.0 it only fired up a few times (typically for about an hour) and then nothing - no data received on my webserver/webservice.
I then started reading up on Android Doze etc. and modified the code so that I now use the AlarmManager.setExactAndAllowWhileIdle - both on my main activity and when resetting the alarm everytime the BroadcastReceiver's OnReceive is hit
Here is the codecode:
override public void OnReceive(Context context, Intent intent)
// Start by set a new alarmtrigger
Intent alarmIntent = new Intent(context, Java.Lang.Class.FromType(typeof(AlarmReceiver)));
var pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
long triggerAtTime = SystemClock.ElapsedRealtime() + (4 * 60 * 1000);
alarmManager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, triggerAtTime, pendingIntent);
My problem is that as soon as I remove my phone from charging cable it doesn't wake from Doze and fires the alarm. It actually even stops working at some point even when it is plugged in. I added some logging info to the part of the code that sets the triggerAtTime and can see that everytime the BroadCastReceiver is triggered the new Alarm is scheduled as the first thing. But after the AlarmManager has been running a few times it is suddently just ignored and nothing happens.
So my experience is like this.
1. Starting the location updates by clicking "Start" on the main activity
2. First alarm is set to start within 5 seconds.
3. The BroadcastReceiver is hit and the new alarm is set (in 10 minutes, also working with 4 minutes and 20 minutes etc.)
4. The broadcastReceiver starts the locationservice and as soon as the device has GPS signal it sends of the location into to my webservice and shuts down.
5. After 10 minutes (exactly) the broadcastreceiver is hit again and the step 3,4,5 is repeating for about an hour. Then after that it stops. BroadcastReceiver isn't hit anymore. No change even if device is powered and keept alive.
I have read multiple times that SetExactAndAllowWhileIdle and SetAndAllowWhileIdle should be used for when the device is idle (in some Doze stage) but maybe I'm missing some permission settings or missed some key build target understanding etc.
Yesterday I tried using the WakefulBroadcastReceiver and StartWakefulService instead but the same issue applied - after about an hour of running smoothly the alarm i just ignored at some point. There are a lot of confusion regarding the 15 / 9 minute interval while using the SetExactAndAllowWhileIdle and I have tried every 20 minutes with the same result.
Main documentation on "SetExactAndAllowWhileIdle" here: https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
My compile/target info is:
Compile using Android version: Android 7.0 (Nougat)
Minimum Android to target: Android 7.0 (API level 24 - Nougat)
Target Android version: Android 7.0 (API level 24 - Nougat)
I have tried to have the app running in both Debug and Release.
I have also tried putting the app in whitelist (Settings > Power > Poweroptimization).
At some point I know that it must be possible to have a background service running that cuts through Doze.
I tried downloading the EverTrack / CorvusGPS app which does exactly what I want and regardless of the device being powered or on battery this app keeps posting location updates every 10 minutes (exactly) no matter what (even on Android 7) so I know that it can be done.
If what I try to accomplish can be done in a different way please let me know but it needs to work in a reliable way so all answers that can get me in the right direction would be helpful. And please feel free to ask anything.
Thanks for reading all that and I look forward hearing from you.
Maybe the folks in Xamarin can post an example of a background location service that runs at an exact interval regardless of the device powersaving mode? I know a lot of developers out there would be happy.
Best regards Søren