I'm using the Firebase console in testing to receive a notification in my iOS. At first it says that I'm connected to Firebase and I receive the Message ID but then I'm having an error Warning: Application delegate received call to -application:didReceiveRemoteNotification:fetchCompletionHandler: but the completion handler was never called. and Unable to connect to FCM. Error Domain=com.google.fcm Code=2001 "(null)" How can I solve this?
Here is my code for didReceiveRemoteNotification
// [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]
Try adding:
completionHandler(UIBackgroundFetchResultNoData);
At the end of your didReceiveRemoteNotification method.
Related
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.");
}
}];
}
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?
I have set up my app to work with GCM.
I have successfully added the code to integrate the GCM in my App.
Now I have two methods to handle the Push Notification:
Default Method
- (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];
}
GCM Method
- (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
// ...
}
Now I am confused where should I Handle my Notificaiton.
Where should I check application state and call my method to handle it.
Should I have to write method in both of these methods.
I'm not familiar with GCM but the two notification methods you listed standard UIApplicationDelegate methods and handle different scenarios.
application:didReceiveRemoteNotification: is called when the app is open and you receive a plain push notification. The types that you get alerted through notification center.
application:didReceiveRemoteNotification:fetchCompletionHandler: is called when the server is letting the app know there's something to download. You check the userInfo for what to download, initiate the download and call the handler(UIBackgroundFetchResult) upon NewData/NoData/Failed
Not sure what GCM does with these two methods but with that info you should be able to figure it out.
You should use GCM Method.
(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
}
In this method, You can handle your notification.
For example,
- (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];
// [START_EXCLUDE]
if(application.applicationState == UIApplicationStateBackground){
//app is in background
}else if(application.applicationState == UIApplicationStateInactive){
//From background to foreground (user touchs notification)
}
handler(UIBackgroundFetchResultNoData);
// [END_EXCLUDE]
}
My app receives push notifications using GCM. My android app works perfectly in that when i completely close the app i still receive notifications however if i do the same with my iOS version i don't receive anything.
Note this will of course be after the app has registered for the first time and then the app is closed. I cant find much information about this. some posts are saying you cant do it. but the likes of facebook and facebook messenger all do it. Does anyone know how this is done?
this is my
DidReceiveRemoteNotification method which is taken from the GCM documentation
// [START ack_message_reception]
- (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]
my payload sent looks like this
$payload = array('registration_ids' => $Regids,
'content_available' => false,
'notification' => array("body"=> $_POST['message'],
"sound" => "default",
'badge' => '1'
)
);
note this works if the app is in the background
I managed to get this working by adding this to my pay load
"priority" => "high"
maybe someone can comment why this worked as i have no idea
It also does work with iOS when the app is closed - if it doesn't, something is wrong.
However, you cannot use silent pushes with iOS when the app was closed by the user (up-swipe in task switcher) - so if your app wants to react on a push without the user having to tap on it, you can't do that when the app was closed.
I Think you are not specifying the alert key in the notification payload. The message provided in the alert key of the notification payload will be displayed on the device when the app is closed.
{
"aps" : { "alert" : "Message received from Bob" },
"acme2" : [ "bang", "whiz" ]
}
In the above payload check the alert key. The Message Message received from Bob will be displayed in the notification center of the iPhone when the app is closed.
My app doesn't receive push notifications when it's not running.
I am trying to handle remote notification sent as JSON and update data in my app using data from given JSON.
All is going well when app is active or in background.
But when app is not running, app is processing notifications only when I open my app by tapping on notification, but not when I open app by tapping on icon.
Here is the code from appDelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Parse setApplicationId:appId
clientKey:clKey];
if (application.applicationState != UIApplicationStateBackground) {
BOOL preBackgroundPush = ![application respondsToSelector:#selector(backgroundRefreshStatus)];
BOOL oldPushHandlerOnly = ![self respondsToSelector:#selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)];
BOOL noPushPayload = ![launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
}
}
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|
UIRemoteNotificationTypeAlert|
UIRemoteNotificationTypeSound|
UIRemoteNotificationTypeNewsstandContentAvailability];
NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
[self processPushNotification:notificationPayload foreground:YES];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
TFLog(#"didRegisterForRemoteNotificationsWithDeviceToken");
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackground];
TFLog(#"deviceToken: %#, currentInstallation.badge: %ld", currentInstallation.deviceToken, (long)currentInstallation.badge);
TFLog(#"deviceToken: %#, deviceType: %#", currentInstallation.deviceToken, currentInstallation.deviceType);
TFLog(#"installationId: %#", currentInstallation.installationId);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
TFLog(#"didFailToRegisterForRemoteNotificationsWithError %#", error);
if (error.code == 3010) {
TFLog(#"Push notifications are not supported in the iOS Simulator.");
} else {
// show some alert or otherwise handle the failure to register.
TFLog(#"application:didFailToRegisterForRemoteNotificationsWithError: %#", error);
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
TFLog(#"%#", userInfo);
[PFPush handlePush:userInfo];
[self processPushNotification:userInfo foreground:YES];
[PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
TFLog(#"didReceiveRemoteNotification2");
[self processPushNotification:userInfo foreground:YES];
[PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
}
As result, app is receiving remote notification in all states, excepting when it is not running.
What have I missed?
You have missed the bit in the Local and Push Notification Programming Guide where it says -
If the action button is tapped (on a device running iOS), the system
launches the application and the application calls its delegate’s
application:didFinishLaunchingWithOptions: method (if implemented); it
passes in the notification payload (for remote notifications) or the
local-notification object (for local notifications).
If the application icon is tapped on a device running iOS, the
application calls the same method, but furnishes no information about
the notification
Also, this note from Apple -
Important: Delivery of notifications is a “best effort”, not
guaranteed. It is not intended to deliver data to your app, only to
notify the user that there is new data available.
If your application is launched from the app icon rather than the notification you need to check for updated content independent of any push notification that may have been received. This enables an application to behave differently when it opens from a notification and when it is opened from the app icon.
For example, the Facebook app opens directly to the item in the notification when launched from the notification alert but not when launched from the app icon - which is the "correct" behaviour from a user point of view. If I interact with the notification then I am interested in its content. If I launch the app from the icon then I just want to use the app - I can then access the notifications in the app if I want.
There's no way you can get the information about your push notification JSON payload when you launch the app by explicitly tapping the app icon.
That's as per Apple's design. When you open the application from any push notification action, then you can retrieve the push notification in application: didFinishLaunchingWithOptions: delegate method. Typically you look up for the UIApplicationLaunchOptionsRemoteNotificationKey key in your launchOptions dictionary.
But, when you open the app by explicitly tapping the application icon, though still the application: didFinishLaunchingWithOptions: delegate will be called, the UIApplicationLaunchOptionsRemoteNotificationKey key will return nil.