Quantcast
Channel: Recent Threads — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 204402

Get Foreground Service to NOT CRASH

$
0
0

Hello All,

I have a Xamarin.Forms app in which I'm trying to get a Foreground Service to run (not crash) in Xamarin.Android. The foreground service that I currently am implementing runs great on Android API <= 25, but anything above that ( >= Android API 26, version 8.0), my app crashes on start-up. I have researched this, and it seems there is a constraint with the API 26 and above foreground services in which when you call StartForegroundService() in your activity, you must call StartForeground() in your service class in less than 5 seconds on runtime (a seemingly pointless constraint). After a lot of Googling, it seems that many people are hacking their code, such as calling StartForeground() more than once, calling StopForeground() before it, etc., to get it to work. I've tried all of these hacks, and I can't get my app to even run. One alternative that I haven't tried as it is more complex, and this is my first Xamarin app, is to implement a Bound Service and call StartForeground() in that, which eliminates the 5 second rule. If need be, I will try that, but there has got to be a way to get a regular foreground service to run on the new Android OS, without hacking your way around it. I have the app running great on my old Galaxy S5 (API 23), so I know this is the issue. Any help or suggestions are greatly appreciated, as I'm scratching my head with this and have put in hours trying to solve it. Here are some snippets of my code...

MainActivity.cs (just OnCreate() method):

protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);
        LockCheck obj = new LockCheck(this);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);

        startIntent = new Intent(this, typeof(ForService));

        if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)   // if API >= 26
            StartForegroundService(startIntent);
        else                                // if API <= 25
            StartService(startIntent);

        LoadApplication(new App());
    }

ForService.cs (foreground service implementation class):

[Service]
public class ForService : Service
{
    public const int FORSERVICE_NOTIFICATION_ID = 10000;
    public const string MAIN_ACTIVITY_ACTION = "Main_activity";
    public const string PUT_EXTRA = "has_service_been_started";

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

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        registerForService();

        Task.Run(async () =>
        {
            await arbitraryMethodInViewModel(); // this method runs an asynchronous timer
        });

        return StartCommandResult.Sticky;
    }

    private void registerForService()
    {
        var notification = new Notification.Builder(this)
            .SetContentTitle("etc")
            .SetContentText("etc")
            .SetSmallIcon(Resource.Drawable.ic_stat_name)
            .SetContentIntent(BuildIntentToShowMainActivity())
            .SetOngoing(true)
            .AddAction(BuildRestartTimerAction())
            .AddAction(BuildStopServiceAction())
            .Build();

        // Enlist this instance of the service as a foreground service, MUST CALL IN < 5 SECONDS ON RUNTIME
        StartForeground(FORSERVICE_NOTIFICATION_ID, notification);
    }

    PendingIntent BuildIntentToShowMainActivity()
    {
        var notificationIntent = new Intent(this, typeof(MainActivity));
        notificationIntent.SetAction(MAIN_ACTIVITY_ACTION);
        notificationIntent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTask);
        notificationIntent.PutExtra(PUT_EXTRA, true);

        var pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.UpdateCurrent);
        return pendingIntent;
    }

    public override void OnDestroy()
    {
        // Remove the notification from the status bar.
        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.Cancel(FORSERVICE_NOTIFICATION_ID);
        StopSelf();
        StopForeground(true);

        base.OnDestroy();
    }
}

Viewing all articles
Browse latest Browse all 204402

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>