Reputation: 41
I am using the CrossGeolocator plugin to subscribe to location updates in a Xamarin Forms application, for Android (for iOS, location updates will continue even when the app is in the background).
I implemented a Foreground Service so that I can continue to get location even while the app goes to the background.
As I understand, I should be able to get location updates if I listen to them in a foreground service.
However, I do not get location updates when the app goes the the background.
My StartCommand of my service datasource:
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Notification notif = DependencyService.Get<INotification>().ReturnNotif();
StartForeground(ServiceRunningNotifID, notif);
CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(10), 0, true, new Plugin.Geolocator.Abstractions.ListenerSettings
{
ActivityType = ActivityType.Other,
PauseLocationUpdatesAutomatically = false,
AllowBackgroundUpdates = true,
DeferLocationUpdates = false,
ListenForSignificantChanges = false,
});
CrossGeolocator.Current.PositionChanged += PositionChanged;
CrossGeolocator.Current.PositionError += PositionError;
return StartCommandResult.Sticky;
}
And events:
private void PositionError(object sender, PositionErrorEventArgs e)
{
Console.WriteLine($"{e.Error}");
}
private void PositionChanged(object sender, PositionEventArgs e)
{
Console.WriteLine($"{e.Position.Latitude}, {e.Position.Longitude}");
}
The events only fire when the app is active. The service starts, and the device shows the notification badge that the service is running.
I have assigned the required permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Can anyone shed some light on the implementation? I can provide additional code if required.
Upvotes: 1
Views: 1643
Reputation: 41
I found the solution by adding this:
ForegroundServiceType = ForegroundService.TypeDataSync | ForegroundService.TypeLocation
As the Service Attribute in the Foreground Service
[Service(ForegroundServiceType = ForegroundService.TypeDataSync | ForegroundService.TypeLocation)]
public class LocationForegroundService : Service
{
...
}
Upvotes: 3
Reputation: 10938
Background updates are handled a bit different on each platform. For Android, you will want to integrate a foreground service that subscribes to location changes and the user interface binds to.
You could use the Xamarin.Essentials and MessagingCenter for this.
[Service]
public class AndroidLocationService : Service
{
CancellationTokenSource _cts;
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource();
Notification notif = DependencyService.Get<INotification>().ReturnNotif();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notif);
Task.Run(() => {
try
{
var locShared = new Location();
locShared.Run(_cts.Token).Wait();
}
catch (OperationCanceledException)
{
}
finally
{
if (_cts.IsCancellationRequested)
{
var message = new StopServiceMessage();
Device.BeginInvokeOnMainThread(
() => MessagingCenter.Send(message, "ServiceStopped")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
if (_cts != null)
{
_cts.Token.ThrowIfCancellationRequested();
_cts.Cancel();
}
base.OnDestroy();
}
}
}
For more details, please check the code sample in the link below. https://stackoverflow.com/a/63665571/11850033
Upvotes: 0