jamesmontemagno / GeolocatorPlugin

Geolocation plugin for Xamarin and Windows
MIT License
294 stars 158 forks source link

Android not keeping service alive in the background #300

Open mivewi opened 5 years ago

mivewi commented 5 years ago

Bug Information

Version Number of Plugin: 4.5.0.6 Device Tested On: Huawei P Smart Simulator Tested On: Version of VS: 2017 - 15.9.7 Version of Xamarin: 3.6.0.264807 Versions of other things you are using: Microsoft.CSharp: 4.5.0 Xamarin.Essentials: 1.0.1 Newtonsoft.Json: 12.0.2

Steps to reproduce the Behavior

1# Implement service as "Klewerro" did in: https://github.com/jamesmontemagno/GeolocatorPlugin/issues/272 2# Start app 3# Set app in background 4# Shut off devices screen

Expected Behavior

Actual Behavior

After 5 mins:

Code snippet

My service code are:

[assembly: Xamarin.Forms.Dependency(typeof(GeolocationService))]
namespace MyApp.Droid.Services
{
[Service]
public class GeolocationService : Service, IGeolocationBackgroundService
{
    private static readonly string CHANNEL_ID = "geolocationServiceChannel";
    public GeolocatorPageViewModel ViewModel { get; private set; }

    public override IBinder OnBind(Intent intent)
    {
        return null;
    }

    public GeolocationService()
    {
        CreateNotificationChannel();
    }

    private void CreateNotificationChannel()
    {
        NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID,
            "GeolocationService", Android.App.NotificationImportance.Default);
        NotificationManager manager = Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;

        manager.CreateNotificationChannel(serviceChannel);

    }

    //[return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        var newIntent = new Intent(this, typeof(MainActivity));
        newIntent.AddFlags(ActivityFlags.ClearTop);
        newIntent.AddFlags(ActivityFlags.SingleTop);

        var pendingIntent = PendingIntent.GetActivity(this, 0, newIntent, 0);

        var builder = new Notification.Builder(this, CHANNEL_ID);
        var notification = builder.SetContentIntent(pendingIntent)
            .SetSmallIcon(Resource.Drawable.ic_media_play_light)
            .SetAutoCancel(false)
            .SetTicker("Locator is recording")
            .SetContentTitle("GeolocationService")
            .SetContentText("Geolocator is recording for position changes.")
            .Build();

        StartForeground(112, notification);
        //ViewModel = new GeolocatorPageViewModel();
        return StartCommandResult.Sticky;
    }

    public void StartService()
        => Forms.Context.StartService(new Intent(Forms.Context, typeof(GeolocationService)));

    public void StartTracking()
    {
        ViewModel = new GeolocatorPageViewModel();
        ViewModel.StartTrackingCommand.Execute(null);
    }
  }
}

It uses a ViewModel which is is implemented like this:

public class GeolocatorPageViewModel
{
    LocationService lservice;
    public GeolocatorPageViewModel()
    {
        lservice = new LocationService();
    }

    public ICommand StartTrackingCommand => new Command(async () =>
    {
        if (CrossGeolocator.Current.IsListening)
        {
            await CrossGeolocator.Current.StopListeningAsync();
        }

        CrossGeolocator.Current.DesiredAccuracy = 100;
        CrossGeolocator.Current.PositionChanged += Geolocator_PositionChanged;

        await CrossGeolocator.Current.StartListeningAsync(
            TimeSpan.FromSeconds(3), 5);
    });

    private void Geolocator_PositionChanged(object sender, PositionEventArgs e)
    {
        var position = e.Position;
        lservice.SendLocationToServerAsync(position.Latitude, position.Longitude, position.Timestamp.DateTime, position.Heading, position.Speed, position.Accuracy, position.Altitude, position.AltitudeAccuracy);
    }
}

I call the service through a interface:

public interface IGeolocationBackgroundService {
    void StartService();
    void StartTracking();
}

I call the service like this:

var svc = DependencyService.Get<IGeolocationBackgroundService>();
svc.StartService();
svc.StartTracking();

Screenshots

Not really applicable.

Other

I'm new to Xamarin and services, and the mydriving app is way to complicated for me, thats why I've used Android background updates SIMPLE example #272

Thanks a lot for looking into my case, I've used a lot of time even getting it to run.

chrisfoulds commented 5 years ago

Huawei phones by default have agressive power management , you have to disable it for your app else it will shut it down regardless of what you do.

https://help.runtastic.com/hc/en-us/articles/212633165-Help-for-GPS-Problems-on-Android-Phones

mivewi commented 5 years ago

Thanks for the answer.

I came from the cordova world and used a similar plugin on the same phone, which I did not shut down in background and the underlaying is still android, so is there any settings I could set on the plugin or do something different, to keep it on longer?

chrisfoulds commented 5 years ago

None that I or any of the major running apps (go on there sites) know about. It's a general android issue on more modern devices.

mivewi commented 5 years ago

Okay I did what it said under huawei, I'm gonna test it and post back here on my findings.

mivewi commented 5 years ago

Still goes out after a few minutes. I'm sure somethings wrong...

chrisfoulds commented 5 years ago

Mine just ran 24hrs in the background. Must be an issue in the way you wrote the notification service.

mivewi commented 5 years ago

Thanks for the reply. Can you share your project so I could test exactly that on my phone? Maybe by sending it in an email?

chrisfoulds commented 5 years ago

It's a commercial application, was a soak test. Did you try running a third party app like runkeeper ? If that keeps working it's your app, if it doesn't it's your phone.

jamesmontemagno commented 5 years ago

You could look to see how we do it here: https://github.com/Azure-Samples/MyDriving/tree/master/src/MobileApps/MyDriving