GCM iOS not receiving push notification - ios

Using GCM for push notification in iOS. Everything is set up nicely. I'm getting registrationToken value & also subscribeToTopic successfully. Connected to GCM. didRegisterForRemoteNotificationsWithDeviceToken method also called. But not getting push notification. didReceiveRemoteNotification method never called. On my android app I'm getting the push notification without any problem. But in iOS notification never received. Here is the source code:
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate{
var gcmSenderID: String?
var registrationToken: String?
let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
var registrationOptions = [String: AnyObject]()
var connectedToGCM = false
let subscriptionTopic = "/topics/global"
var subscribedToTopic = false
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
if application.respondsToSelector("registerUserNotificationSettings:") {
let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Register for Push Notifications before iOS 8
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
let gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("remote notification")
GCMService.sharedInstance().appDidReceiveMessage(userInfo);
}
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
GCMService.sharedInstance().appDidReceiveMessage(userInfo);
NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
userInfo: userInfo)
handler(UIBackgroundFetchResult.NoData);
}
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData ) {
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
// [END get_gcm_reg_token]
}
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
func registrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.registrationToken = registrationToken
print("Registration Token: \(registrationToken)")
self.subscribeToTopic()
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
}
}
func subscribeToTopic() {
// topic
if(registrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(self.subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
self.subscribedToTopic = true;
NSLog("Subscribed to \(self.subscriptionTopic)");
}
})
}
}
func applicationDidBecomeActive(application: UIApplication) {
print("applicationDidBecomeActive")
self.globalPrice = CartLocalData.getTotalPrice()
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
self.subscribeToTopic()
print("Connected to GCM")
// ...
}
})
}
}
What am I doing wrong. Can anyone suggest??

you should have the option to turn on push from capabilities section. You also need to build separate key/cert pair in the apple member center and have those included on your machine. here is a screenshot from a new project i made.
It sounds like maybe one of the steps in the process might not be done.
Start over again and try to figure out what your missing. here is a ray wenderlich tutorial that walks you through the steps here
And the link to Apple developer site that talks about it in depth here

Related

How to display only once same push notifications?

I'm using push notifications on my app, and i didn't find a way to display only once notifications that have same content.
Is that possible ?
My code :
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UIAlertViewDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {
var window: UIWindow?
var gcmSenderID: String?
var registrationOptions = [String: AnyObject]()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: [category]))
UIApplication.sharedApplication().registerForRemoteNotifications()
let gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print(error.localizedDescription)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
GCMService.sharedInstance().appDidReceiveMessage(userInfo)
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
GCMService.sharedInstance().disconnect()
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
GCMService.sharedInstance().connectWithHandler({(error:NSError?) -> Void in
if let error = error {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
print("Connected to GCM")
}
})
}
func onTokenRefresh() {
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID, scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
func registrationHandler(registrationToken: String!, error: NSError!) {
if(registrationToken != nil) {
print(registrationToken)
}else{
print("Registration to GCM failed with error: \(error.localizedDescription)")
}
}
}
I'm using Google Cloud Messaging for push notification into my app
Thank's in advance

Not Receiving Push Notifications (And Out of Troubleshooting Ideas)

I have what seems like should be a working push notification in an iOS app. Here's the meat of it. What's driving me nuts is that everything appears to work, except that my breakpoints are never hit in the message receiver functions; device registration with Google Cloud Notifications is successful, the initialization code appears to work and I even get "Success" messages back from the GCM service.
STILL, I never seem to actually get the message in my app. Note, I'm running it in an iPad connected to my Mac and everything seems kosher/enabled in Notifications settings. Also, I'm using the dev certificate to match the kGGLInstanceIDAPNSServerTypeSandboxOption:true option.
What could I be missing?
import UIKit
import Google
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate {
var window: UIWindow?
var gcmSenderID: String?
var registrationToken: String?
var registrationOptions = [String: AnyObject]()
let messageKey = "onMessageReceived"
let registrationKey = "onRegistrationCompleted"
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
//********************************
//*** Never Hits Breakpoint ******
//********************************
print("Notification received: \(userInfo)")
// Handle the received message
NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
userInfo: userInfo)
}
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
//********************************
//*** Never Hits Breakpoint ******
//********************************
NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
userInfo: userInfo)
handler(UIBackgroundFetchResult.NoData);
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
// ...
// Register for remote notifications
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
// Override point for customization after application launch.
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError ) {
print("Registration for remote notification failed with error: \(error.localizedDescription)")
// [END receive_apns_token_error]
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
registrationKey, object: nil, userInfo: userInfo)
}
func registrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.registrationToken = registrationToken
print("Registration Token: \(registrationToken)")
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
}
}
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
}
Message sent to https://gcm-http.googleapis.com/gcm/send. The payload is arbitrary/copied from a sample.
{
"content-available":1,
"data": {
"score": "5x1",
"time": "15:10"
},
"to" : "<<the registration token resulting from the code above>>"
}
...which results in the reply:
{
"multicast_id": 12345...,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "some ID"
}
]
}
Any ideas?
Please try following command in your terminal by substituting your GCM registration token and Server API key.. this command helps me.
Please make sure payload dictionary must be notification not
data
curl --header "Authorization: key=” https://android.googleapis.com/gcm/send -d '{"to”:””,”priority":"high”, “notification":{"title”:”TEST TITLES”,”body":"Wow ! your first message tested.","badge":"1","sound":"default"}}'
Also try checking by app sending in background CMD + H

GCM Notifications in background IOS / php Server

It's been a week since I have tried to implement GCM notifications on my iOS app. Foreground notifications are working but not background.
Here is my code from appdelegate and my server :
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {
var window: UIWindow?
let constants = Constants()
var connectedToGCM = false
var subscribedToTopic = false
var gcmSenderID: String?
var registrationToken: String?
var registrationOptions = [String: AnyObject]()
var notificationWasReceivedInForeground = true
let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
let subscriptionTopic = "/topics/global"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Google Maps
GMSServices.provideAPIKey("apiKey")
// Initial View Controller
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var initialViewController = storyboard.instantiateViewControllerWithIdentifier("navConFirst")
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.boolForKey(constants.userIsConnected) {
initialViewController = storyboard.instantiateViewControllerWithIdentifier("navConConnection")
}
// Google Cloud Messaging
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
let gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
if(registrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(self.subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
self.subscribedToTopic = true;
NSLog("Subscribed to \(self.subscriptionTopic)");
}
})
}
}
// [START connect_gcm_service]
func applicationDidBecomeActive( application: UIApplication) {
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
// [START_EXCLUDE]
self.subscribeToTopic()
// [END_EXCLUDE]
}
})
}
// [END connect_gcm_service]
// [START disconnect_gcm_service]
func applicationDidEnterBackground(application: UIApplication) {
GCMService.sharedInstance().disconnect()
// [START_EXCLUDE]
self.connectedToGCM = false
// [END_EXCLUDE]
}
// [END disconnect_gcm_service]
// [START receive_apns_token]
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData ) {
// [END receive_apns_token]
// [START get_gcm_reg_token]
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
// [END get_gcm_reg_token]
}
// [START receive_apns_token_error]
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError ) {
print("Registration for remote notification failed with error: \(error.localizedDescription)")
// [END receive_apns_token_error]
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
registrationKey, object: nil, userInfo: userInfo)
}
// [START ack_message_reception]
func application( application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Notification received: \(userInfo)")
// This works only if the app started the GCM service
GCMService.sharedInstance().appDidReceiveMessage(userInfo);
// Handle the received message
// [START_EXCLUDE]
NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
userInfo: userInfo)
// [END_EXCLUDE]
}
func application( application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
print("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(messageKey, object: nil,
userInfo: userInfo)
handler(UIBackgroundFetchResult.NoData);
// [END_EXCLUDE]
}
// [END ack_message_reception]
func registrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.registrationToken = registrationToken
print("Registration Token: \(registrationToken)")
self.subscribeToTopic()
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
}
}
// [START on_token_refresh]
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
// [END on_token_refresh]
// [START upstream_callbacks]
func willSendDataMessageWithID(messageID: String!, error: NSError!) {
if (error != nil) {
// Failed to send the message.
} else {
// Will send message, you can save the messageID to track the message
}
}
func didSendDataMessageWithID(messageID: String!) {
// Did successfully send message identified by messageID
}
// [END upstream_callbacks]
func didDeleteMessagesOnServer() {
// Some messages sent to this device were deleted on the GCM server before reception, likely
// because the TTL expired. The client should notify the app server of this, so that the app
// server can resend those messages.
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
}
for the server :
$regId = "myID";
$message = "message";
$data = array( 'price' => $message, 'sound' => 'default', 'body' => 'helloworld', 'title' => 'default', 'badge' => 12);
$ids = array( $regId);
sendGoogleCloudMessage( $data, $ids );
function sendGoogleCloudMessage( $data, $ids )
{ $apiKey = apiKey;
$url = 'https://android.googleapis.com/gcm/send';
$post = array(
'to' => "myID",
'data' => $data,
'priority' => "high",
);
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $post ) );
$result = curl_exec( $ch );
if ( curl_errno( $ch ) )
{
echo 'GCM error: ' . curl_error( $ch );
}
curl_close( $ch );
echo $result;
}
Here is the thing : if I add content_availble or if I change "data" to "notification" like I read here, the notifications don't work anymore and I get the error "not registered"
If someone sees what is wrong I would be really gratefull !
Thanks in advance
It seems my certificates weren't valid. I had to download this certificate and install it
new WWDR Certificate that expires in 2023

is there automatic re-try to get GCM token (ios swift)?

I use this code to get GCM token (APNS and then GCM tokens).
Does retry happens automatically when GCM doesn't return token?
If so - where can i see it in code? and how often does this happen?
//push
// [START register_for_remote_notifications]
func registerForRemoteNotifications(application: UIApplication, launchOptions:[NSObject: AnyObject]?) -> Bool {
// [START_EXCLUDE]
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
pushManager.gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
// [END_EXCLUDE]
// Register for remote notifications
if #available(iOS 8.0, *) {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Fallback
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
}
// [END register_for_remote_notifications]
// [START start_gcm_service]
let gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = pushManager
GCMService.sharedInstance().startWithConfig(gcmConfig)
// [END start_gcm_service]
return true
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings)
{
UIApplication.sharedApplication().registerForRemoteNotifications()
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
if(pushManager.registrationToken != nil && pushManager.connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(pushManager.registrationToken, topic: pushManager.subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(self.pushManager.subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
self.pushManager.subscribedToTopic = true;
NSLog("Subscribed to \(self.pushManager.subscriptionTopic)");
}
})
}
}
// [START connect_gcm_service]
func connectGcmService( application: UIApplication) {
if (self.pushManager.connectedToGCM == true)
{
return
}
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.pushManager.connectedToGCM = true
print("Connected to GCM")
// [START_EXCLUDE]
self.subscribeToTopic()
// [END_EXCLUDE]
}
})
}
// [END connect_gcm_service]
// [START disconnect_gcm_service]
func disconnectGcmService(application: UIApplication) {
GCMService.sharedInstance().disconnect()
// [START_EXCLUDE]
self.pushManager.connectedToGCM = false
// [END_EXCLUDE]
}
// [END disconnect_gcm_service]
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData ) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for i in 0..<deviceToken.length {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
print("tokenString: \(tokenString)")
pushManager.receiveApnsToken( application, deviceToken: deviceToken)
}
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError ) {
pushManager.receiveApnsTokenError( application, error: error)
}
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
pushManager.ackMessageReception( application, userInfo: userInfo)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
pushManager.ackMessageReception( application, userInfo: userInfo)
}
and PushManager class:
public class PushManager: NSObject, GGLInstanceIDDelegate, GCMReceiverDelegate {
var connectedToGCM = false
var subscribedToTopic = false
var gcmSenderID: String?
var registrationToken: String?
var registrationOptions = [String: AnyObject]()
let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
let subscriptionTopic = "/topics/global"
// // [START register_for_remote_notifications]
func registerForRemoteNotifications(application: UIApplication, launchOptions: [NSObject: AnyObject]?) -> Bool {
// [START_EXCLUDE]
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
// [END_EXCLUDE]
// Register for remote notifications
if #available(iOS 8.0, *) {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Fallback
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
}
// [END register_for_remote_notifications]
// [START start_gcm_service]
let gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
// [END start_gcm_service]
return true
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
if(registrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(self.subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
self.subscribedToTopic = true;
NSLog("Subscribed to \(self.subscriptionTopic)");
}
})
}
}
// [START connect_gcm_service]
func connectGcmService( application: UIApplication) {
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
// [START_EXCLUDE]
self.subscribeToTopic()
// [END_EXCLUDE]
}
})
}
// [END connect_gcm_service]
// [START disconnect_gcm_service]
func applicationDidEnterBackground(application: UIApplication) {
GCMService.sharedInstance().disconnect()
// [START_EXCLUDE]
self.connectedToGCM = false
// [END_EXCLUDE]
}
// [END disconnect_gcm_service]
// [START receive_apns_token]
public func receiveApnsToken( application: UIApplication, deviceToken: NSData ) {
// [END receive_apns_token]
// [START get_gcm_reg_token]
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
// [END get_gcm_reg_token]
}
// [START receive_apns_token_error]
public func receiveApnsTokenError( application: UIApplication, error: NSError ) {
print("Registration for remote notification failed with error: \(error.localizedDescription)")
// [END receive_apns_token_error]
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
registrationKey, object: nil, userInfo: userInfo)
}
// [START ack_message_reception]
func ackMessageReception( application: UIApplication, userInfo: [NSObject : AnyObject]) {//, fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Notification received: \(userInfo)")
// This works only if the app started the GCM service
GCMService.sharedInstance().appDidReceiveMessage(userInfo);
...
}
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
print("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(messageKey, object: nil,
userInfo: userInfo)
handler(UIBackgroundFetchResult.NoData);
// [END_EXCLUDE]
}
// [END ack_message_reception]
func registrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.registrationToken = registrationToken
print("Registration Token: \(registrationToken)")
self.subscribeToTopic()
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
}
}
// [START on_token_refresh]
public func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
Based on the docs, If registration fails, the client app is recommended to retry. In cases where GCM is not essential to the client app's functioning, the app could ignore the registration error and try to register again the next time it starts. Otherwise, it should retry the registration operation using exponential back-off (the client app should wait twice the previous amount of time before retrying). Once your client app has a registration token, it can receive messages through the GCM APNs interface.
To handle cases where registration token has been refreshed, the GGLInstanceIDDelegate protocol declares an onTokenRefresh method that is called when the system determines that tokens need to be refreshed.
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}

iOS GCM notification sending, but not showing

I'm trying to implement GCM in my iOS app. Everything seems to work fine, the app is connecting to GCM and getting a registration ID back. If I send a notification to that regid using Postman it works and I get a success response back from Google. However, whatever I try, the notification isn't actually shown on the device.
The post messsage to the GCM servers I'm using is
{
"to" : "RegID",
"content_available" : true,
"notification" : {
"body" : "Test Body",
"title" : "Test Title"
}
}
which gives me the response:
{
"multicast_id": 6594175386712804014,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1443445858075083%c4cfa24dc4cfa24d"
}
]
}
This makes me believe there is something wrong with the code in my app. Below I've pasted all the relevant code. I've written the code 3 times without success, first following the tutorial and editing it to fit in my app properly, second time I copied the code from the tutorial and the third time I got the example app from the Github repo and copied everything relevant to GCM over.
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var connectedToGCM = false
var gcmSenderID: String?
var registrationToken: String?
var registrationOptions = [String: AnyObject]()
let defaults = NSUserDefaults.standardUserDefaults()
let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
let notification = "isNotificationEnabled"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Google Cloud Messaging
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
var types: UIUserNotificationType = UIUserNotificationType.Badge |
UIUserNotificationType.Alert |
UIUserNotificationType.Sound
var settings: UIUserNotificationSettings =
UIUserNotificationSettings( forTypes: types, categories: nil )
application.registerUserNotificationSettings( settings )
application.registerForRemoteNotifications()
var gcmConfig = GCMConfig.defaultConfig()
GCMService.sharedInstance().startWithConfig(gcmConfig)
return true
}
func applicationDidBecomeActive(application: UIApplication) {
GCMService.sharedInstance().connectWithHandler({
(NSError error) -> Void in
if error != nil {
println("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
println("Connected to GCM")
// ...
}
})
}
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData ) {
println(deviceToken)
// [END receice_apns_token]
// [START get_gcm_reg_token]
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
var instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
// [END get_gcm_reg_token]
}
func registrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.registrationToken = registrationToken
println("Registration Token: \(registrationToken)")
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
} else {
println("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(
self.registrationKey, object: nil, userInfo: userInfo)
}
}
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
println("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
func application( application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("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(messageKey, object: nil,
userInfo: userInfo)
}
If anyone asked a similar question before let me know, I wasn't able to find one that described my situation properly.
Thanks in advance!
You haven't implemented the appropriate notification callback. You need to implement
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// Do something with userInfo
// call fetchCompletionHandler with the appropriate UIBackgroundFetchResult
}
Silent Push Notifications(i.e. ones with content-available flag set) call the above UIApplicationDelegate method instead of application:didReceiveRemoteNotification:.
Also make sure you've added remote-notification value to the UIBackgroundModes in your Info.plist.

Resources