2

After reading APNS documentation, I have implemented apns into my app. Everything works fine, but I have a question. I don't know if it is possible, but I would like to do a task when my app is in background and I receive a apns notification.

This is my dictionary inside the notification:

aps =
{
  alert = "message";
  sound = "default";
};

If my app is in foreground, I execute this code:

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{     
    [HTTPConnection sendGetToUrl:[NSURL URLWithString:stringUrl]];

    NSLog(@"Received notification: %@", userInfo);  
}

But apns does not execute "didReceiveRemoteNotification" when the app is in background, so I would like to execute the method:

[HTTPConnection sendGetToUrl:[NSURL URLWithString:stringUrl]];

if I receive an apns notification in background.

Is there any way to do it?

Thanks so much!

kemmitorz
  • 351
  • 7
  • 18

3 Answers3

6

Yes this is posible since iOS 7, you will need to add remote-notification to the UIBackgroundModes in your apps info.plist .

Then implement the application:didReceiveRemoteNotification:fetchCompletionHandler: in your app delegate. You will have 30 seconds to fetch data, if you app takes longer the system might terminate your.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler {
   NSString *stringURl = /* some URL */;
   [HTTPConnection sendGetToUrl:[NSURL URLWithString:stringUrl]];

   // Once done call handler with one of the result types:
   // UIBackgroundFetchResultNewData, UIBackgroundFetchResultNoData, UIBackgroundFetchResultFailed

   handler(UIBackgroundFetchResultNewData);
}

You will have to notify the system when the call is done and that data is fetched by call the handler. As stated by the documentation you will need to tell the handler if you succeeded to fetch any data:

handler

The block to execute when the download operation is complete. When calling this block, pass in the fetch result value that best describes the results of your download operation. You must call this handler and should do so as soon as possible. For a list of possible values, see the UIBackgroundFetchResult type.

rckoenes
  • 69,092
  • 8
  • 134
  • 166
  • 1
    Thanks! But...how could I get the received data? I mean, my "sendGetToUrl" receives data to store in CoreData, and I have auxiliar methods to store those data. Could I call to these method also to store the received data?. And, when I must call the completion handler? After o before saving data? Thanks! – kemmitorz Feb 28 '14 at 10:12
  • 1
    How you call the fetch method of your data is totally up to you, it is very depended on your app design. I would call the `handler` after receiving the data, just before you save. You could do the save with the `beginBackgroundTaskWithExpirationHandler` to make sure your app is not suspended while saving. – rckoenes Feb 28 '14 at 10:29
  • 1
    I don't know if I am doing something wrong... But this does not work exactly as I want... Suppose I am in background and I receive the apns notification (then I receive and save the data in background), but if I set the "airplane mode ON" before enter the app, and without internet connection I enter the app, the data is not saved. What i'm doing wrong? – kemmitorz Feb 28 '14 at 14:15
2

Source from Apple Documentation:

          -(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
      fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{


          }

Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running, the system calls this method regardless of the state of your app. If your app is suspended or not running, the system wakes up or launches your app and puts it into the background running state before calling the method.

When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the handler block as soon as possible after downloading the needed data. If you do not call the handler in time, your app is suspended. More importantly, the system uses the elapsed time to calculate power usage and data costs for your app’s background downloads. For more information about supporting background operations in response to push notifications, see “App States and Multitasking” in iOS App Programming Guide.

Tom updates: However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.

  • 2
    Does this hold true even if the app is killed by the user? (http://finerthings.in/featured/ios-7-background-multitasking-killing-apps/) – vinnybad Dec 19 '14 at 17:13
  • Also from the docs: `However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.` – Tom Jun 06 '16 at 15:57
  • @Tom Yes, you were right, I have updated my answer. Thanks dude! you could also update the any answer if it is right :) – Vijay-Apple-Dev.blogspot.com Jun 08 '16 at 06:20
0

If you mean, after the user taps the notification, then you should check if UIApplicationLaunchOptionsRemoteNotificationKey exists in - (BOOL)application:didFinishLaunchingWithOptions:, for example:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSDictionary *rNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if(remoteNotifDic)
    {
        NSString *myAlertString=rNotif[@"aps"][@"alert"];
        //...
    }
}
gWiz
  • 1,274
  • 9
  • 12