5

I want to check whether my app was launched for background fetch in my application delegate's didFinishLaunchingWithOptions. There is nothing in launchOptions dictionary. So is there any way to check it?

I know that I can check applicationState, but for some reason sometimes it returns UIApplicationStateBackground, even if I launch app normally.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if (application.applicationState != UIApplicationStateBackground) {
    // Analytics initialization code
    }
}

I've created breakpoint at Analytics initialization code and sometimes it enters to this block even if I launch app normally!

I know that I can detect the state later when applicationDidBecomeActive or applicationDidEnterBackground will be called. If I will use these approach to detect the state I need to move my Analytics initialization code to some other place. If it remain in application:didFinishLaunchingWithOptions: it will be called every time when my app starts background fetch. So maybe I should just move Analytics initialization code to some other method and don't check applicationState in application:didFinishLaunchingWithOptions:? If so which method I can use for this?

tagirkaZ
  • 469
  • 7
  • 19
  • 1
    You can simulate a background refresh in the simulator. I would try looking at the [UIApplication sharedApplication] applicationState] to see if it reports it's in the background. – Gary Riches Feb 04 '15 at 11:23
  • I already tried it. But for some reason sometimes it returns UIApplicationStateBackground even when I launch app normally! – tagirkaZ Feb 04 '15 at 12:39
  • @tagirkaZ You mean when you launch your app normally and you detect UIApplicationStateBackground in your didFinishLaunchingWithOptions? – CarmeloS Feb 06 '15 at 13:08
  • Why do you need to know about the launch reason in `application:didFinishLaunchingWithOptions:`? I would try to clean up that implementation so that it doesn't do too much and get rid of the need to know about the launch reason. Basically just set up the window and initialize potential SDKs, etc. I'd then do everything related to background fetching in `application:performFetchWithCompletionHandler:`. Maybe if you paste some code or just pseudo code about what are you doing, I can help further. – Jernej Strasner Feb 06 '15 at 13:23
  • @CarmeloS yes! I launch app normally and check applicationState and sometimes it returns UIApplicationStateBackground. – tagirkaZ Feb 06 '15 at 13:59
  • I think this is impossible, I suggest that you turn off your background fetch feature and check if it is still possible to launch with a background state – CarmeloS Feb 06 '15 at 14:00
  • @JernejStrasner I have analytics and some other SDKs initialization in `application:didFinishLaunchingWithOptions:`. It's important to not initialize analytics when my app run in background since it will cause wrong statistics of my app usage. Will analytics actually work in the background? And what are other proper places to start analytics? – tagirkaZ Feb 06 '15 at 14:27
  • Also my initial view controller's `viewDidLoad` method get called when I simulated background fetch. Is it normal? I don't want to execute the code that in `viewDidLoad` in background mode. I've added some code that checks `applicationState` and if it's `UIApplicationStateBackground ` it calls `return`. I've put breakpoint to this `return` call and sometimes it reaches this line of code even if I launch app normally. – tagirkaZ Feb 06 '15 at 14:44
  • @CarmeloS it is possible AFAIK e.g. if you launch for beacons or gps – Daij-Djan Feb 09 '15 at 08:46
  • Maybe you can try to check if you have a push notification payload in launch options `UIApplicationLaunchOptionsRemoteNotificationKey` – tmpz Feb 09 '15 at 09:19
  • I completely agree with @JernejStrasner wrt to cleaning up the implementation. But if you still need to know how just check all the types of launch options each of the key and if you are using 8.0 or greater UIApplicationLaunchOptionsUserActivityTypeKey can tell if it is user interaction or not. Else handle the it in the application:performFetchWithCompletionHandler: . – Edwin Abraham Feb 10 '15 at 13:58

4 Answers4

5

Take a look at slides 19-21 of this presentation: http://www.slideshare.net/moliver816/background-fetch

Immediately upon launch, you can check if applicationState equals UIApplicationStateBackground in order to determine whether your app was launched into the background.

Otherwise, if you just want to know when your app is fetching data for background app refresh, you can do so inside the UIApplicationDelegate method application:performFetchWithCompletionHandler:.

badAPI
  • 122
  • 3
  • 1
    thank you for the link you provided! I know that I should check the state. But sometimes it's UIApplicationStateBackground even if I launch app normally! – tagirkaZ Feb 10 '15 at 15:13
  • Can you post the code you're using to check? This should not be possible. – badAPI Feb 10 '15 at 15:22
  • In my case, `UIApplication.shared.applicationState` always returns `inactive` in `didFinishLaunchingWithOptions`. – Kimi Chiu Sep 26 '20 at 07:43
1

You can wrap you analytics initialization code in a singleton using GCD dispatch once. That way you know it only runs one time per application load. Resume from background or any other states won't matter since the lifecycle is still continuous.

+ (Analytics*)sharedInstance
  {
     static dispatch_once_t onceToken;
     static Analytics* sharedInstance;
     dispatch_once(& onceToken, ^{
         sharedInstance = [[self alloc] init];
         //Do analytics initialization code here
      });
     return sharedInstance;
  }
zimmryan
  • 1,099
  • 10
  • 19
0

Try this one

[[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(AppIsInBackground:)
                                                     name:UIApplicationDidEnterBackgroundNotification
                                                   object:nil];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(AppIsActive:)
                                                     name:UIApplicationDidBecomeActiveNotification
                                                 object:nil];

you have to call the selector : NSNotificationCenter is calling AppIsInBackground Selector (App in background)

- (void) AppIsInBackground:(NSNotification *) notification {
 //Shut down the memory/processor intensive things and save any states for when the app is reinitialized
}
sarra.srairi
  • 150
  • 14
  • `applicationDidEnterBackground` and `applicationDidBecomeActive` are both call after `application:didFinishLaunchingWithOptions:`. So this approach is not useful for me. – tagirkaZ Feb 10 '15 at 15:10
0

following is the delegate method which is called when the background fetch is performed by the iOS for our application.

This is a appDelegate method.

func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { }