Forum Cross Platform with Xamarin

Local Notifications for beacons with Estimotes.xplat when Android process killed

I am using Xamarin.Forms with Estimotes.xplat (PCL). My app is running perfectly in iOS, even when killed, beacons events come and I could create a local notifications.

My problem comes when in Android I kill the application. If the app is not killed, notifications and events are triggered. If the application is killed, nothing appears to happen. The BeaconService, I checked and it is alive. For notifications I use the Acr or the CrossLocalNotifications (both PCL).

I could guess two things: one, the notifications need a context and the context used is gone (i do not know how to use the service context in this particular case with estimotes.xplat), two: the event is not triggered even.

It is kinda hard to guess what is going on when the application is killed.

Is there any way to make it in the PCL? Am I missing something?

Thank you very much in advance!

Posts

  • RodyLagerwaardRodyLagerwaard USMember ✭✭

    Same problem here. Did you find a solutions?

  • AllanRitchieAllanRitchie CAInsider, University ✭✭✭

    You need to make your own sticky service in android to keep your app alive.

    The estimote background service is not sticky or boot persistent so not to make assumptions about your app

  • Alejandro-lAlejandro-l JPMember ✭✭

    @AllanRitchie thank you Allan for your great work and answer! I will do as you said and post the solution.

  • Alejandro-lAlejandro-l JPMember ✭✭

    I have been learning a bit about sticky services and here is what I came to think;

    The Xamarin Estimote SDK BeaconService seems sticky already and running whether you kill the parent activity or not. This service should make a call on a registered callback once you enter a beacons area. The call should throw an event in the Estimotes.Droid and that call should arrive to my RegionStatusChanged.

    Until here fine if the application is in sleeping or alive. When it gets destroyed, the BeaconService is still running but the call seems not to happen anymore. I tried by creating natively a file if the call was done (meanwhile the activity is killed) with no success.

    The sticky part should be done on the SDK BeaconService by extending it or something?

  • Alejandro-lAlejandro-l JPMember ✭✭

    @RodyLagerwaard Have you managed to solve it? I still cannot figure it out :(

  • RodyLagerwaardRodyLagerwaard USMember ✭✭

    @Alejandro.3470 unfortunately I have not found a way to make it work. @AllanRitchie could you please provide a small sample how to create a sticky service to keep the monitoring alive on Android. That would be very helpfull, thanks in advance!

  • RodyLagerwaardRodyLagerwaard USMember ✭✭

    I think it's running ok now. I can reboot the device and close the app and monitoring still seems to work.
    The only scenario it does not work if the user kills your app via the Settings > Application. Don't know if there is a solution for this scenario.

    I created a Service and a BroadcastReciever (for the reboot) to get it to work. All the monitoring code I moved form the Xamarin.Forms app to the Service in the Android app.

    This is wat the Service looks like:

    [Service]
    public class AppMonitorBeaconService : Service
    {
        int StartId = -1;
    
        public override IBinder OnBind(Intent intent)
        {
            return null;
        }
    
        public override void OnCreate()
        {
            base.OnCreate();
        }
    
        public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
        {
            if (StartId == -1)
            {
                if (GetRunningServices().Where(x => x == "AppMonitorBeaconService").Count() == 0)
                {
                    var t = new Thread(() =>
                    {
    
                        Log.Info("MonitorBeacons", "Start Beacon Service at {2}, flags={0}, startid={1}", flags, startId, DateTime.UtcNow);
                        var task = System.Threading.Tasks.Task.Run(async () =>
                        {
                            await StartBeaconService();
    
                        });
                    }
                 );
                 t.Start();
                }
            }
            StartId = startId;
    
            return StartCommandResult.Sticky;
        }
    
        private IEnumerable<string> GetRunningServices()
        {
            var manager = (ActivityManager)GetSystemService(ActivityService);
            return manager.GetRunningServices(int.MaxValue).Select(
                service => service.Service.ClassName).ToList();
        }
    
        async System.Threading.Tasks.Task StartBeaconService()
        {
            Application.SynchronizationContext.Post(_ => { EstimoteManager.Instance.Initialize().ContinueWith(x => OnBeaconMgrInit(x.Result)); }, null);
        }
    
        void OnBeaconMgrInit(BeaconInitStatus status)
        {
    
            if (status != BeaconInitStatus.Success)
                return;
    
            if (Beacons == null)
                return;
    
            if (Beacons.Count() == 0)
                return;
            EstimoteManager.Instance.RegionStatusChanged += OnBeaconRegionStatusChanged;
            EstimoteManager.Instance.StopAllMonitoring();
            //Start adding your regions
            //EstimoteManager.Instance.StartMonitoring();
        }
    
        async void OnBeaconRegionStatusChanged(object sender, BeaconRegionStatusChangedEventArgs args)
        {
            //Do your stuff when entered or removed
        }
    
        public override void OnDestroy()
        {
            base.OnDestroy();
            Log.Debug("MonitorBeacons", "Beacon Service destroyed at {0}.", DateTime.Now);
        }
    }
    

    In your MainApplication you can start the service:
    AppContext.StartService(new Intent(AppContext, typeof(AppMonitorBeaconService)));

    For the reboot you can add this:

     [BroadcastReceiver]
        [IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted }, Categories = new[] { Android.Content.Intent.CategoryDefault })]
        class AppRebootBroadcast : BroadcastReceiver
        {
            public override void OnReceive(Context context, Intent intent)
            {
                if (intent.Action == Intent.ActionBootCompleted)
                {
                    context.ApplicationContext.StartService(new Intent(context.ApplicationContext, typeof(AppMonitorBeaconService)));
                }
            }
        }
    

    Dont forget to add the permissions "android.permission.RECEIVE_BOOT_COMPLETED"to the manifest.

  • Alejandro-lAlejandro-l JPMember ✭✭
    edited June 2016

    Wow, so many thanks! I will have it a look and try later to understand it and implement it in my app.

    The only scenario it does not work if the user kills your app via the Settings > Application. Don't know if there is a solution for this scenario.

    Have you tried without using the debugging? I had a similar issue and when I was connected to the debug, the service just plainly dies and never restarts even if it is Sticky, using Settings > Application to kill it. I do not know why though or if it even makes sense but happened to me haha :smile:

  • RodyLagerwaardRodyLagerwaard USMember ✭✭

    Hmm, just tried it in release mode, but still does not work when you kill it via the settings.

Sign In or Register to comment.