Google Cloud Messaging: Do not receive alerts when an iOS application is in the background

I followed this tutorial https://developers.google.com/cloud-messaging/ios/client to implement GCM in my iOS app. My application server is a Google application engine written in Java, and I use the gcm-server.jar library https://github.com/google/gcm . I think my certificates are great and I can register, get a token and even get the contents of messages sent by my application server. However, I do not receive notifications when the application is in the background, I always receive it only when I click the application icon to restart it.

I thought it was because I only implemented didReceiveRemoteNotification: and not didReceiveRemoteNotification:fetchCompletionHandler: so I implemented it instead of the first, but I don't get a notification in the background, and worse, the application crashes, saying something like "unrecognized selector sent to didReceiveRemoteNotification: instance" somehow was wrong in userInfo. I have enabled background mode in xCode as required for it. Here is the code I'm using:

 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 < 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 

Can someone figure out what I am not getting, if not in the foreground?

EDIT : Java code used on the server side to send a GCM message:

 public static MulticastResult sendViaGCM(String tag, String message, List<String> 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; } 

EDIT2: POST request screenshots http://image.noelshack.com/fichiers/2015/34/1440193492-gcm1.png http://image.noelshack.com/fichiers/2015/34/1440193502-gcm2.png

EDIT3: The request I am now sending from my application server:

 public static void sendGCMMessage(String tag, String message, List<String> 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(); } 
+6
source share
2 answers

Based on the GCM documentation, you can set content_available to true .

(In iOS, this field is used to represent content available in the APNS payload. When a notification or message is sent, and this value is true, the inactive client application wakes up. In Android, data messages awaken the default application. In Chrome, it is not currently supported. )

content_available corresponds to Apple content-available , which you can find in this Apple Notification Service documentation .

In addition, you should use Download notifications to send a message to your iOS application so that it can display a banner when your application is in the background.

Here is an example HTTP request:

 https://gcm-http.googleapis.com/gcm/send Content-Type:application/json Authorization:key=API_KEY { "to" : "REGISTRATION_TOKEN", "notification" : { "sound" : "default", "badge" : "1", "title" : "default", "body" : "Test", }, "content_available" : true, } 

The Java library is just a sample, you can add other fields to it. For example, in the Message.java class, you can add two private variables, one of which is private final Boolean contentAvailable , the other is private final Map<String, String> notification .

You can try the HTTP request in your terminal by doing curl -i -H "Content-Type:application/json" -H "Authorization:key=API_KEY" -X POST -d '{"to":"REGISTRATION_TOKEN", "notificaiton":{"sound":"default", "badge":"1", "title": "default", "body":"test",},"content_available":true}' https://android.googleapis.com/gcm/send or try it in Postman .

Edited by:

If your application has been interrupted and you want push notifications to be displayed on your device, you can set a high priority in your HTTP request body (beware that setting your messages to a high priority contributes more to battery leakage than regular priority messages )

Example HTTP request:

 { "to" : "REGISTRATION_TOKEN", "notification" : { "sound" : "default", "badge" : "1", "title" : "default", "body" : "Test", }, "content_available" : true, "priority" : "normal", } 
+11
source

I had the same problem, I could not get a notification about the topic when the application was killed, this POST is working now, I had to add priority.

  { "to" : "/topics/offers", "notification" : { "sound" : "default", "badge" : "1", "body" : "Text", }, "priority" : "high", } 
+4
source

All Articles