1

This issue exists in both Android and iOS

iOS

Background fetch is triggering the app to start up normally, i.e. running the AppDelegate.FinishedLaunching method.

this method along with initialization of syncfusion controls creates an instance of the app

LoadApplication(new App());

The follow through of this is that it also creates an instance of my regular app pages, and then runs the OnAppearing methods which download data from the web. Meanwhile this is happening the background fetch is running as intended from AppDelegate.PerformFetch.

However the background fetch finishes before the OnAppearing web request completes, the background fetch then suspends the app. A second background fetch starts later and only runs the AppDelegate.PreformFetch which seems to resume the app and causes the HttpClient from the original OnAppearing request to throw a timeout error. The user then opens the app later and is presented with the exception dialog

The AppDelegate.FinishedLaunching method has a parameter UIApplication this has the property BackgroundTimeRemaining.

When the app is run normally this property is set to Double.MaxValue, however when manually running a background fetch via setting iOS Run Options, Execution Mode to BackgroundFetch this property is closer to 30.0, matching the 30 seconds to run a background fetch.

Despite this in the scenario I described above the BackgroundTimeRemaining is Double.MaxValue when the background fetch is triggered as above

How can I prevent the app from starting as described, is there a property I can check to see if the app is only trying to do a background fetch, or adjust the fetch to never also launch the FinishedLaunching method.

Android

I have so far been unable to as accurately diagnose, however it seems to be the same issue

MainActivty.OnCreate starts the app with

LoadApplication(new App());

while the JobScheduler has started my DownloadService to run a web request similar to the iOS PreformFetch method

Hopefully that fully explains my issue, if not I can clarify further

public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    public Action BackgroundSessionCompletionHandler { get; set; }

    //App starts here
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.Init();
        bool isInBackground = false;
        if (app.BackgroundTimeRemaining != double.MaxValue) //This check is failing
        {
            isInBackground = true;
        }
        else
        {
            //3rd party initialization
            UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
        }
        LoadApplication(new App(isBackground: isInBackground));
        return base.FinishedLaunching(app, options);
    }

    //App gets to here later
    public override async void PerformFetch(UIApplication application, Action<UIBackgroundFetchResult> completionHandler)
    { 
        DataSync dataSync = new DataSync(); 
        await dataSync.RunBackgroundSync();
    }
}
public partial class App : Xamarin.Forms.Application
{
    public App(bool isBackground = false)
    {
        InitializeComponent();
        IsInBackgroud = isBackground;
        Database.Initialize();
        if (!IsInBackgroud)
        {
            MainPage = new FlyoutPage(); 
            //Flyout page the creates instances of my regular views, 
            //Once those pages are created this chain of events ends
            //Then a race condition begins for the OnAppearing method which runs a web request
            //And the AppDelegete PreformFetch Method
        }
    }
}
Finlay Brown
  • 11
  • 1
  • 2
  • Can’t we set a flag when AppDelegate.PerformFetch occurs then in finish launching, check the flag to determine if we need to Load(app)! I haven’t tried but just a thought! – N Subedi Sep 28 '22 at 03:05
  • The problem is that FinishedLaunching and Load(app) finish before the PreformFetch method starts so setting the flag there is a race condition before the OnAppearing web request starts – Finlay Brown Sep 28 '22 at 03:33
  • Based on the details here https://stackoverflow.com/questions/27877335/ios-background-fetch it was supposed to call application:performFetchWithCompletionHandler when iOS tries to background fetch.. and given that you should be able to handle your scenario.. I haven't tried it personally. but You should override: public override void PerformFetch(UIApplication application, Action completionHandler) – N Subedi Sep 28 '22 at 15:57
  • That is targeted for native ios rather than forms. however I am overriding "public override void PerformFetch(UIApplication application, Action completionHandler)" the issue is that that is called after my other events for starting the app have already been called – Finlay Brown Sep 28 '22 at 20:46
  • You may have a look at the documentation for performFetchWithCompletionHandler : "https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623125-application". – Hongxin Sui-MSFT Sep 29 '22 at 02:36

0 Answers0