FCM notification is not working in iOS app - ios

I am integrating FCM notification and cloud messaging in my app. I have followed exactly same steps mentioned in Firebase doc. Even I have tried with sample code given by FCM. It is just throwing some warnings as:
<FIRInstanceID/WARNING> Failed to fetch APNS token Error Domain=com.firebase.iid Code=1001 "The operation couldn’t be completed. and <FIRMessaging/WARNING> FIRMessaging registration is not ready with auth credentials.
My code written in Appdelegate.m is:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Register for remote notifications
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// iOS 7.1 or earlier
UIRemoteNotificationType allNotificationTypes =
(UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
[application registerForRemoteNotificationTypes:allNotificationTypes];
} else {
// iOS 8 or later
// [END_EXCLUDE]
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
// [START configure_firebase]
[FIRApp configure];
// [END configure_firebase]
// Add observer for InstanceID token refresh callback.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tokenRefreshNotification:)
name:kFIRInstanceIDTokenRefreshNotification object:nil];
return YES;
}
// [START receive_message]
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
NSLog(#"Message ID: %#", userInfo[#"gcm.message_id"]);
// Pring full message.
NSLog(#"%#", userInfo);
}
// [END receive_message]
// [START refresh_token]
- (void)tokenRefreshNotification:(NSNotification *)notification {
// Note that this callback will be fired everytime a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
// Connect to FCM since connection may have failed when attempted before having a token.
[self connectToFcm];
// TODO: If necessary send token to appliation server.
}
// [END refresh_token]
// [START connect_to_fcm]
- (void)connectToFcm {
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
}
}];
}
// [END connect_to_fcm]
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self connectToFcm];
}
// [START disconnect_from_fcm]
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[FIRMessaging messaging] disconnect];
NSLog(#"Disconnected from FCM");
}
// [END disconnect_from_fcm]

It appears that you need to have the "priority" set to "high" if you want the notification to get displayed while the app is in the background:
Firebase IOS push notification doesn't work when app is closed

I was doing the same thing with my iOS app. FCM and GCM DO NOT WORK with iOS. No matter what anyone says there is no chance that it will work. I spend 2 weeks and went everywhere on the net asking and looking a post. iOS will only accept APNS push notification . Save your self the headache and start with apps.
EDIT:
Here is the newest repository for FCM. Give this a shot and see what comes of it.
https://github.com/firebase/quickstart-ios
It seems a little different than the one I tried when I was working on my iOS version.
#Chris, is this the code branch that you used to implement your version?

I am also having same kind of issue. I get "Connected to FCM" message and token and seems everything integrated perfectly, yet unable to receive any notification.
However, I received notification at once but then after without any code change and certificate changes or removal, I am unable to receive any further notifications.
Check my code here, it's a cocos2d app.
func didLoadFromCCB()
{
...
setupPushNotification()
}
func setupPushNotification () {
let application = UIApplication.sharedApplication()
// 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)
}
FIRApp.configure()
// Add observer for InstanceID token refresh callback.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "tokenRefreshNotification:",
name: kFIRInstanceIDTokenRefreshNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBecomeActive:", name: UIApplicationDidBecomeActiveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didEnterBackground:", name: UIApplicationDidEnterBackgroundNotification, object: nil)
}
// [START refresh_token]
func tokenRefreshNotification(notification: NSNotification) {
let refreshedToken = FIRInstanceID.instanceID().token()!
print("InstanceID token: \(refreshedToken)")
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
// [END refresh_token]
// [START connect_to_fcm]
func connectToFcm() {
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
}
}
// [END connect_to_fcm]
func didBecomeActive(application:UIApplication) {
NSLog("Did Become Active")
connectToFcm()
}
func didEnterBackground(application: UIApplication) {
NSLog("Did enter background")
FIRMessaging.messaging().disconnect()
NSLog("Disconnected from FCM.")
}
}
I don't know how I got that only one correct notification then it turned tables. :(
Let me know how to resolve this.,

try sending this
curl --header "Authorization: key={YOUR_API_KEY}" --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send -d "{\"to\":\"{YOUR_DEVICE_TOKEN}\",\"content_available\":true,\"priority\":\"high\",\"notification\":{\"title\":\"TEST\",\"sound\":\"default\",\"body\":\"IT WORKS!\",\"badge\":1}}"
It works for me. (Obviously, register for push notifications first then print out the device token)

Related

Unable to get FCM token on real device but getting on simulator

I have integrated Firebase cloud messaging in my iOS application without cocoa pods. Firebase analytics is working fine. But FCM token is received on simulator but not real device. On real device I keep getting error
Failed to fetch default token Error Domain=com.firebase.iid Code=501
"(null)"
I have uploaded the .p12 certificates for development and prod on Firebase
I have checked the bundle ID for my app and that on Firebase console
I have Push notification enable on my App ID.
Here is my code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[FIRApp configure];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tokenRefreshNotification:) name:kFIRInstanceIDTokenRefreshNotification object:nil];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
// For iOS 10 data message (sent via FCM)
[FIRMessaging messaging].remoteMessageDelegate = self;
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[[FIRInstanceID instanceID] setAPNSToken:deviceToken type:FIRInstanceIDAPNSTokenTypeSandbox];
}
- (void)tokenRefreshNotification:(NSNotification *)notification {
// Note that this callback will be fired everytime a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
// Connect to FCM since connection may have failed when attempted before having a token.
[self connectToFcm];
// TODO: If necessary send token to application server.
}
- (void)connectToFcm {
// Won't connect since there is no token
if (![[FIRInstanceID instanceID] token]) {
return;
}
// Disconnect previous FCM connection if it exists.
[[FIRMessaging messaging] disconnect];
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM. FCM token - %#", [[FIRInstanceID instanceID] token] );
}
}];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[FBSDKAppEvents activateApp];
[self connectToFcm];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[FIRMessaging messaging] disconnect];
NSLog(#"Disconnected from FCM");
}
Please help.
I got solution to my own problem. The device's date and time was incorrect. The second I changed it to current date & time, Firebase started giving me FCM token and got connected properly. I have checked the push notification as well from Firebase Notification Console. It is working in a way better than I imagined.
May be the issue is due the version problem.Actually me also faced the same problem.I got the FCM token on simulator but not on the device.The reason is due to registering the User notifications setting on didFinishLaunchingWithOptions..... We have to check the version on both device and simulator... If both are not same..please check the " [[UIApplication sharedApplication] registerUserNotificationSettings:settings] "
conditions for the current device version... Bcz I restricted this for >= 10 versions in didFinishLaunchingWithOptions....

InvalidParameterException from Amazon SNS when using Firebase Cloud Messaging token from iOS

I am actually trying to integrate FCM push notification feature in iOS. I created an account in the Firebase console and I am able to send notifications to the app, but problem is when I try from InvalidParameterException, I registered application in Amazon SWS, there I am getting an exception while sending notification to app.
Crash log:
Caused by: com.amazonaws.services.sns.model.InvalidParameterException: Invalid parameter: Token Reason: iOS device tokens must be 64 hexadecimal characters (Service: AmazonSNS; Status Code: 400; Error Code: InvalidParameter; Request ID: 6df7d1e9-0455-5d27-a2e7-818bd3b434f0)
integration code:
token:
eZkS-MKTCUo:APA91bFlaaure5iHcHFUBjdw_c-yyWmQp4H3OGeeb-mh6QIHSLyzehoKrM4_dbtLm3wPBrMi-vTxsHZ44pc8VNhLsOZ3H7sdhoa2WpCjpcyEZhRiJQiBiCQzGFmK7O5chAkf0pnkn2rj
code:
- (void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
NSLog(#"Message ID: %#", userInfo[#"gcm.message_id"]);
// Print full message.
NSLog(#"%#", userInfo);
}
// [END receive_message]
// [START ios_10_message_handling]
// Receive displayed notifications for iOS 10 devices.
// [END ios_10_message_handling]
// [START refresh_token]
- (void)tokenRefreshNotification:(NSNotification *)notification {
// Note that this callback will be fired everytime a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
// Connect to FCM since connection may have failed when attempted before having a token.
[self connectToFcm];
// TODO: If necessary send token to application server.
}
// [END refresh_token]
// [START connect_to_fcm]
- (void)connectToFcm {
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
}
}];
}

iOS Firebase Push Notifications not receive in device using obj c

Integrate Firebase cloud messaging in my application. Successfully install pod and get all the framework. I want to get the refreshedToken for my device and send the notification and receive in my device, and want to track all the button click in my app.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// iOS 7.1 or earlier
UIRemoteNotificationType allNotificationTypes =
(UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
[application registerForRemoteNotificationTypes:allNotificationTypes];
} else {
// iOS 8 or later
// [END_EXCLUDE]
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
// [START configure_firebase]
[FIRApp configure];
// [END configure_firebase]
// Add observer for InstanceID token refresh callback.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tokenRefreshNotification:)
name:kFIRInstanceIDTokenRefreshNotification object:nil];
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
NSLog(#"Message ID: %#", userInfo[#"gcm.message_id"]);
// Pring full message.
NSLog(#"%#", userInfo);
}
- (void)connectToFcm {
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
}
}];
}
- (void)tokenRefreshNotification:(NSNotification *)notification {
// Note that this callback will be fired everytime a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
// Connect to FCM since connection may have failed when attempted before having a token.
[self connectToFcm];
// TODO: If necessary send token to appliation server.
}
- (void)applicationWillResignActive:(UIApplication *)application {
// 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.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[FIRMessaging messaging] disconnect];
// 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.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self connectToFcm];
}
I'm using this code in app delegate. Got these waring in my code. How can I fix this issues. new for development help me.
WARNING: Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
FCMAPP[496:56073] Configuring the default app.
Failed to fetch APNS token Error Domain=com.firebase.iid Code=1001 "(null)"
FIRMessaging library version 1.1.0
Firebase Analytics v.3200000 started
To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled
FIRMessaging registration is not ready with auth credentials
FCMAPP[496:56073] Unable to connect to FCM. Error Domain=com.google.fcm Code=501 "(null)"
Use the following Swift code.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
if #available(iOS 10.0, *)
{
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.currentNotificationCenter().delegate = self
UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions([.Badge, .Sound, .Alert]) { (granted, error) in
if granted
{
//self.registerCategory()
}
}
// For iOS 10 data message (sent via FCM)
FIRMessaging.messaging().remoteMessageDelegate = self
}
else
{
let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert,.Badge,.Sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
//Configuring Firebase
FIRApp.configure()
// Add observer for InstanceID token refresh callback.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotification), name: kFIRInstanceIDTokenRefreshNotification, object: nil)
return true
}
//Receive Remote Notification on Background
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
{
FIRMessaging.messaging().appDidReceiveMessage(userInfo)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
{
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Prod)
}
func tokenRefreshNotification(notification: NSNotification)
{
if let refreshedToken = FIRInstanceID.instanceID().token()
{
print("InstanceID token: \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
func connectToFcm()
{
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil)
{
print("Unable to connect with FCM. \(error)")
}
else
{
print("Connected to FCM.")
}
}
}
func applicationDidBecomeActive(application: UIApplication)
{
connectToFcm()
}
Have you set up the application correctly on the Firebase dashboard?
I have encountered this error before, as the Cloud Messaging settings aren't too obvious on the Firebase console.
Open the Firebase console. Click the cog next to your application name and go on "Project Settings".
Select the cloud messaging tab. You'll need to add your iOS APNS certificates here to successfully send push messages (One for development, one for production).
I was getting this error as I hadn't correctly uploaded my apps certificates.
Update:
Another reason for this error that i've encountered this error is that the Firebase SDK sometimes can't obtain the APNS token from apple itself. To resolve this, i've obtained the token manually:
First register for remote notifications:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
// Register for remote notifications.
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
When the APNS token is returned, manually set it on the Firebase instance:
- (void)application:(UIApplication *)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
NSLog(#"Registered for notification device token: %#", devToken);
[[FIRInstanceID instanceID] setAPNSToken:devToken type:FIRInstanceIDAPNSTokenTypeUnknown];
[self connectToFcm];
const void *devTokenBytes = [devToken bytes];
}
Should then successfully be able to connect to Firebase cloud messaging:
- (void)connectToFcm {
NSLog(#"Connecting to FCM...");
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
}
}];
}
If you cannot obtain the APNS token this way, there is something wrong with your push notification setup on the apple member center. Have you generated a developer/release APNS certificate and added them to your provision profile?

How to register for push notifications AFTER login/register?

I need to register the user into the installation class in Parse after they login/register, but it does not register. There is no error printed, and when I breakpoint in the appdeleagate nothing happens.
viewDidLoad of viewcontroller after login/register
override func viewDidLoad() {
super.viewDidLoad()
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound, .Badge], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
AppDelegate
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation["user"] = PFUser.currentUser()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if (error == nil){
print("saved installation")
}else{
print("error \(error)")
}
})
}
To register to receive push notifications via Apple Push Service you have to call a registerForRemoteNotifications() method of UIApplication.
If registration succeeds, the app calls your app delegate object’s application:didRegisterForRemoteNotificationsWithDeviceToken: method and passes it a device token.
You should pass this token along to the server you use to generate push notifications for the device. If registration fails, the app calls its app delegate’s application:didFailToRegisterForRemoteNotificationsWithError: method instead.
you can refer this Appcoda's beginner guide for push notifiction
Update :
#pragma mark - push notificaiton
-(void)registerToReceivePushNotification {
// Register for push notifications
UIApplication* application =[UIApplication sharedApplication];
[application registerForRemoteNotificationTypes:
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound];
}
nd the two application delegate callbacks are in app delegate
// handle user accepted push notification, update parse
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken {
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:newDeviceToken];
// enable future push to deviceId
NSUUID *identifierForVendor = [[UIDevice currentDevice] identifierForVendor];
NSString* deviceId = [identifierForVendor UUIDString];
[currentInstallation setObject:deviceId forKey:#"deviceId"];
[currentInstallation saveInBackground];
}
// handle push notification arrives when app is open
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
}
You can do the registration call at any time - and it is a good idea to only do so when you know in the app you would like the user to receive push notifications.
The two application delegate callbacks have to be in your app delegate though, as you register for notification types on the application delegate and you only have one. I would suggest making an application delegate method to call that then does the registration, you could call it from your view controller through [[UIApplication sharedApplication] delegate] (cast the result of that call to your application delegate class).
code is in objective-c convert it in swift.
hope this will help :)

ios Google Cloud Messaging (GCM) not receiving remote notifications

Problem:
iOS isn't receiving any remote notifications from GCM, but can't find any information relating to why this would be the case.
First time implementing push notifications, not sure what the cause of problem is.
Situation:
I am currently working on the iOS version of an app that uses GCM for push notifications. Notifications are being received fine on Android, however, it doesn't appear to be receiving at all on iOS.
When I run the application, the console shows me that everything is fine, has a token, connected to GCM and subscribed to topics
app[579:45511] Registration Token:
bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1pLTQ/8t-5QNiXbYwZYEWiSFD-frQKlsV8lgI
app[579:45511] Connected to GCM
app[579:45511] Already subscribed to /topics/global
However it doesn't receive any notifications and when I pull down Notifications Center or pull up Control Center, the following message occurs in console
app[579:45511] Could not connect to GCM: The operation couldn’t be completed. (com.google.gcm error 2001.)
which doesn't tell me much other than referring to...
/// Missing KeyPair.
kGGLInstanceIDOperationErrorCodeMissingKeyPair = 2001,
On the other-hand, when I send it to the background with the multi-task feature and bring it back, I get this again:
app[579:45511] Connected to GCM
app[579:45511] Already subscribed to /topics/global
Setup:
I've followed the GCM instructions to set up in iOS and even referred to the GcmExample.xcodeproj for the implementation (to the point that the code is exact same).
Set the info.plist for 'Required background modes' -> 'App downloads content in response to push notifications'
Came across another stackoverflow question (can't find now) about GCM and IPs not being whitelisted but ruled that out to not be the issue.
Code:
#import "AppDelegate.h"
#interface AppDelegate ()
#property(nonatomic, strong) void (^registrationHandler) (NSString *registrationToken, NSError *error);
#property(nonatomic, assign) BOOL connectedToGCM;
#property(nonatomic, strong) NSString* registrationToken;
#property(nonatomic, assign) BOOL subscribedToTopic;
#end
NSString *const SubscriptionTopic = #"/topics/global";
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// [START_EXCLUDE]
_registrationKey = #"onRegistrationCompleted";
_messageKey = #"onMessageReceived";
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
NSError* configureError;
[[GGLContext sharedInstance] configureWithError:&configureError];
if (configureError != nil) {
NSLog(#"Error configuring the Google context: %#", configureError);
}
_gcmSenderID = [[[GGLContext sharedInstance] configuration] gcmSenderID];
// [END_EXCLUDE]
// Register for remote notifications
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
// [END register_for_remote_notifications]
// [START start_gcm_service]
[[GCMService sharedInstance] startWithConfig:[GCMConfig defaultConfig]];
// [END start_gcm_service]
__weak typeof(self) weakSelf = self;
// Handler for registration token request
_registrationHandler = ^(NSString *registrationToken, NSError *error){
if (registrationToken != nil) {
weakSelf.registrationToken = registrationToken;
NSLog(#"Registration Token: %#", registrationToken);
[weakSelf subscribeToTopic];
NSDictionary *userInfo = #{#"registrationToken":registrationToken};
[[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey
object:nil
userInfo:userInfo];
} else {
NSLog(#"Registration to GCM failed with error: %#", error.localizedDescription);
NSDictionary *userInfo = #{#"error":error.localizedDescription};
[[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey
object:nil
userInfo:userInfo];
}
};
[[NSNotificationCenter defaultCenter] postNotificationName:_messageKey
object:nil
userInfo:nil];
return YES;
}
- (void)subscribeToTopic {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
if (_registrationToken && _connectedToGCM) {
[[GCMPubSub sharedInstance] subscribeWithToken:_registrationToken
topic:SubscriptionTopic
options:nil
handler:^(NSError *error) {
if (error) {
// Treat the "already subscribed" error more gently
if (error.code == 3001) {
NSLog(#"Already subscribed to %#",
SubscriptionTopic);
} else {
NSLog(#"Subscription failed: %#",
error.localizedDescription);
}
} else {
self.subscribedToTopic = true;
NSLog(#"Subscribed to %#", SubscriptionTopic);
}
}];
}
}
- (void)applicationWillResignActive:(UIApplication *)application {
// 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.
}
// [START disconnect_gcm_service]
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 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];
// [START_EXCLUDE]
_connectedToGCM = NO;
// [END_EXCLUDE]
}
// [END disconnect_gcm_service]
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 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.
// 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 {
_connectedToGCM = true;
NSLog(#"Connected to GCM");
// [START_EXCLUDE]
[self subscribeToTopic];
// [END_EXCLUDE]
}
}];
}
// [END connect_gcm_service]
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
// [START receive_apns_token]
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// [END receive_apns_token]
// [START get_gcm_reg_token]
// Start the GGLInstanceID shared instance with the default config and request a registration
// token to enable reception of notifications
[[GGLInstanceID sharedInstance] startWithConfig:[GGLInstanceIDConfig defaultConfig]];
_registrationOptions = #{kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:#YES};
[[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID
scope:kGGLInstanceIDScopeGCM
options:_registrationOptions
handler:_registrationHandler];
// [END get_gcm_reg_token]
}
// [START receive_apns_token_error]
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Registration for remote notification failed with error: %#", error.localizedDescription);
// [END receive_apns_token_error]
NSDictionary *userInfo = #{#"error" :error.localizedDescription};
[[NSNotificationCenter defaultCenter] postNotificationName:_registrationKey
object:nil
userInfo:userInfo];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"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]
}
- (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:_messageKey
object:nil
userInfo:userInfo];
handler(UIBackgroundFetchResultNoData);
// [END_EXCLUDE]
}
// [END ack_message_reception]
// [START on_token_refresh]
- (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:_gcmSenderID
scope:kGGLInstanceIDScopeGCM
options:_registrationOptions
handler:_registrationHandler];
}
// [END on_token_refresh]
#end
UPDATE
backend php code to send a GCM message
//------------------------------
// Payload data you want to send
// to Android device (will be
// accessible via intent extras)
//------------------------------
$msg = addslashes($_POST["msg"]);
//------------------------------
// The recipient registration IDs
// that will receive the push
// (Should be stored in your DB)
//
// Read about it here:
// http://developer.android.com/google/gcm/
//------------------------------
//------------------------------
// Call our custom GCM function
//------------------------------
sendGoogleCloudMessage( $msg );
echo "send";
//------------------------------
// Define custom GCM function
//------------------------------
function sendGoogleCloudMessage( $msg )
{
//------------------------------
// Replace with real GCM API
// key from Google APIs Console
//
// https://code.google.com/apis/console/
//------------------------------
$apiKey = 'abc';
//------------------------------
// Define URL to GCM endpoint
//------------------------------
$url = 'https://android.googleapis.com/gcm/send';
//------------------------------
// Set CURL request headers
// (Authentication and type)
//------------------------------
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
//------------------------------
// Initialize curl handle
//------------------------------
$ch = curl_init();
//------------------------------
// Set URL to GCM endpoint
//------------------------------
curl_setopt( $ch, CURLOPT_URL, $url );
//------------------------------
// Set request method to POST
//------------------------------
curl_setopt( $ch, CURLOPT_POST, true );
//------------------------------
// Set our custom headers
//------------------------------
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
//------------------------------
// Get the response back as
// string instead of printing it
//------------------------------
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
//------------------------------
// Set post data as JSON
//------------------------------
$post_json_encode = '{"data":{"message":"' . $msg . '"},"to":"/topics/global"}';
curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_json_encode );
//------------------------------
// Actually send the push!
//------------------------------
$result = curl_exec( $ch );
//------------------------------
// Error? Display it!
//------------------------------
if ( curl_errno( $ch ) )
{
echo 'GCM error: ' . curl_error( $ch );
}
//------------------------------
// Close curl handle
//------------------------------
curl_close( $ch );
//------------------------------
// Debug GCM response
//------------------------------
$arr_result = json_decode($result, true);
foreach ($arr_result as $name => $value) {
echo "<p>".$name .": ". $value ."</p>";
}
}
The error 2001 you get is NOT kGGLInstanceIDOperationErrorCodeMissingKeyPair but rather kGCMServiceErrorCodeAlreadyConnected. The latter means that you're already connected to GCM. To better debug this I would try to send a display notification to the device token i.e. send this
$post_json_encode = '{"notification":{"body":"' . $msg .
'"},"to":"/topics/global"}';
You should theoretically connect to GCM when your app is in the foreground and disconnect when you go to background. You can then reconnect again when you come to the foreground.
The data payload and notification payload are both applicable on iOS & Android. On iOS the difference is that notification payload is sent through APNS while data payload is sent through GCM's own connection which is only there when app is in foreground. In Android notification payload is the new display notification stuff added recently.
I was facing the same issue on iOS. Then I found the solution on PushBots website. It is working fine for me now.
In XCode go to Targets > Build settings > Code Signing Identity
and make sure it's not automatic and set to the profile matching certificate linked to the application ID for example

Resources