title: Google Cloud Messaging: don't receive alerts when iOS App is in background
body: <p>I have followed this tutorial <a href="https://developers.google.com/cloud-messaging/ios/client" rel="noreferrer">https://developers.google.com/cloud-messaging/ios/client</a> to implement GCM on my iOS Application. My app server is a google app engine written in Java and I use the gcm-server.jar <a href="https://github.com/google/gcm" rel="noreferrer">https://github.com/google/gcm</a> library. I think my certificates are fine and I can register, get a token and even receive the content of the messages sent by my app server. However, I don't receive any notification alerts when the app is in background, I always receive it only when I click on the app icon to restart it.</p>
  
  <p>I thought that was because I was only implementing <code>didReceiveRemoteNotification:</code> and not <code>didReceiveRemoteNotification:fetchCompletionHandler:</code> so I implemented it instead of the first one but I don't receive notifications while in background either and worse, the app crashes saying something like"unrecognized selector sent to instance didReceiveRemoteNotification:" like something was wrong in the userInfo. I did allow background modes in xCode like required for it. Here is the code I use:</p>
  
  <pre><code>AppDelegate ()
  
  @property (nonatomic, strong) NSDictionary *registrationOptions;
  @property (nonatomic, strong) GGLInstanceIDTokenHandler registrationHandler;
  
  @end
  
  @implementation AppDelegate
  
  
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  
  //-- Set Notification
  [[GCMService sharedInstance] startWithConfig:[GCMConfig defaultConfig]];
  if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
  {
      NSLog(@"Case iOS8");
      // iOS 8 Notifications
      [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
  
      [application registerForRemoteNotifications];
  }
  else
  {
      NSLog(@"Case iOS7");
      // iOS &lt; 8 Notifications
      [application registerForRemoteNotificationTypes:
       (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
  }
  
  self.registrationHandler = ^(NSString *registrationToken, NSError *error){
      if (registrationToken != nil) {
  
          NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
          [defaults setObject:registrationToken forKey:TOKENGCM];
          NSLog(@"Registration Token: %@", registrationToken);
          //some code
      } else {
          NSLog(@"Registration to GCM failed with error: %@", error.localizedDescription);
      }
  };
  return YES;
  }
  
  - (void)applicationWillResignActive:(UIApplication *)application {
  }
  
  - (void)applicationDidEnterBackground:(UIApplication *)application {
  [[GCMService sharedInstance] disconnect];
  }
  
  - (void)applicationWillEnterForeground:(UIApplication *)application {
  }
  
  - (void)applicationDidBecomeActive:(UIApplication *)application {
  // Connect to the GCM server to receive non-APNS notifications
  [[GCMService sharedInstance] connectWithHandler:^(NSError *error) {
      if (error) {
          NSLog(@"Could not connect to GCM: %@", error.localizedDescription);
      } else {
          NSLog(@"Connected to GCM");
          // ...
      }
  }];
  }
  
  - (void)applicationWillTerminate:(UIApplication *)application {
  }
  
  
  - (void)application:(UIApplication *)application
  didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  // Start the GGLInstanceID shared instance with the default config and request a registration
  // token to enable reception of notifications
  [[GGLInstanceID sharedInstance] startWithConfig:[GGLInstanceIDConfig defaultConfig]];
  self.registrationOptions = @{kGGLInstanceIDRegisterAPNSOption:deviceToken,
                           kGGLInstanceIDAPNSServerTypeSandboxOption:@NO};
  [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:SENDER_ID
                                                      scope:kGGLInstanceIDScopeGCM
                                                    options:self.registrationOptions
                                                    handler:self.registrationHandler];
  }
  
  - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
  NSLog(@"Error in registration. Error: %@", err);
  }
  
  - (void)onTokenRefresh {
  // A rotation of the registration tokens is happening, so the app needs to request a new token.
  NSLog(@"The GCM registration token needs to be changed.");
  [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:SENDER_ID
                                                      scope:kGGLInstanceIDScopeGCM
                                                    options:self.registrationOptions
                                                    handler:self.registrationHandler];
  }
  
  
  - (void)application:(UIApplication *)application
  didReceiveRemoteNotification:(NSDictionary *)userInfo {
  NSLog(@"Notification received: %@", userInfo);//This does print the content of my message in the console if the app is in foreground
  UIApplicationState state = [application applicationState];
  if (state == UIApplicationStateActive) {
      NSString *cancelTitle = @"Close";
      NSString *showTitle = @"Show";
      NSString *message = [[userInfo valueForKey:@"aps"] valueForKey:@"alert"];
      UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Some title"
                                                          message:message
                                                         delegate:self
                                                cancelButtonTitle:cancelTitle
                                                otherButtonTitles:showTitle, nil];
      [alertView show];
  }
  else{
      NSLog(@"Notification received while inactive");
      [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99];
      UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
                                                     message:@"app was INACTIVE"
                                                    delegate:self
                                           cancelButtonTitle:@"a-ha!"
                                           otherButtonTitles:nil];
      [BOOM show];
      NSLog(@"App was NOT ACTIVE");
     [[NSNotificationCenter defaultCenter] postNotificationName:@"Notification!"
                                                          object:nil
                                                        userInfo:userInfo];
  }
  // This works only if the app started the GCM service
  [[GCMService sharedInstance] appDidReceiveMessage:userInfo];
  }
  
  //Implement that causes unrecognized selector crash 
  - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
  NSLog(@"Notification received: %@", userInfo);
  // This works only if the app started the GCM service
  [[GCMService sharedInstance] appDidReceiveMessage:userInfo];
  // Handle the received message
  // Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
  // [START_EXCLUDE]
  [[NSNotificationCenter defaultCenter] postNotificationName:@"notif"
                                                      object:nil
                                                    userInfo:userInfo];
  handler(UIBackgroundFetchResultNoData);
  // [END_EXCLUDE]
  }
  
  @end
  </code></pre>
  
  <p>Can someone figure out what I don't receive notifications when not in foreground?</p>
  
  <p><strong>EDIT</strong>: the Java code used on the server side to send the GCM message:</p>
  
  <pre><code>public static MulticastResult sendViaGCM(String tag, String message, List&lt;String&gt; deviceIdsList) throws IOException {
      Sender sender = new Sender(Constantes.API_KEY);
      // This message object is a Google Cloud Messaging object
      Message msg = new Message.Builder().addData("tag",tag).addData("message", message).build();
      MulticastResult result = sender.send(msg, deviceIdsList, 5);
      return result;
  }
  </code></pre>
  
  <p><strong>EDIT2:</strong> screenshots of the POST Request 
  <a href="http://image.noelshack.com/fichiers/2015/34/1440193492-gcm1.png" rel="noreferrer">http://image.noelshack.com/fichiers/2015/34/1440193492-gcm1.png</a>
  <a href="http://image.noelshack.com/fichiers/2015/34/1440193502-gcm2.png" rel="noreferrer">http://image.noelshack.com/fichiers/2015/34/1440193502-gcm2.png</a></p>
  
  <p><strong>EDIT3:</strong> the request I now send from my app server:</p>
  
  <pre><code>public static void sendGCMMessage(String tag, String message, List&lt;String&gt; deviceIdsList) {
      String request = "https://gcm-http.googleapis.com/gcm/send";
      try{
          URL url = new URL(request);
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          conn.setDoOutput(true);
          //conn.setInstanceFollowRedirects(false);
          conn.setRequestMethod("POST");
          //Les deux headers obligatoires:
          conn.setRequestProperty("Content-Type", "application/json");
          conn.setRequestProperty("Authorization", "key=" + API_KEY);
          //Construction du JSON:
          JSONObject fullJSON = new JSONObject();
          JSONObject data=new JSONObject();
          JSONObject notification=new JSONObject();
          data.put("tag", tag);
          data.put("message", message);
          notification.put("sound", "default");
          notification.put("badge", "1");
          notification.put("title", "default");
          notification.put("body", message);
          fullJSON.put("registration_ids", deviceIdsList);
  
          fullJSON.put("notification", notification);
          fullJSON.put("content_available", "true");
          fullJSON.put("data", data);
  
          //Phase finale:
          OutputStreamWriter wr= new OutputStreamWriter(conn.getOutputStream());
          wr.write(fullJSON.toString());
          wr.flush();
          wr.close();//pas obligatoire
          //conn.setUseCaches(false);
      }
      catch(Exception e){
          e.printStackTrace();
      }
  </code></pre>