Is there a way to send silent or mixed remote notifications with bluemix? There is no such option in the dashboard.
I want my app to fetch data while it's in background when receiving a remote notification.
Edit (copy-paste from comment):
I meant what is the way to send mixed push notifications from Bluemix side, not how to handle it client side. The solution is to use REST API:
POST https://mobile.eu-gb.bluemix.net/imfpush/v1/apps/$(app_id)/messages
with body:
"settings": { "apns": { "type":'MIXED' }
Handling of notifications is done client-side and what you're wanting to do is certainly possible. Taking from the Bluemix Documentation for Push Notifications linked here
Silent notifications do not appear on the device screen. These notifications are received by the application in the background, which wakes up the application for up to 30 seconds to perform the specified background task. A user might not be aware of the notification arrival.
To handle silent push notifications, implement the following method in appDelegate.m.
// For Objective C
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
{
NSNumber *contentAvailable = userInfo[#"aps"][#"content-available"];
if([contentAvailable intValue]== 1){
[[IMFPushClient sharedInstance] application:application didReceiveRemoteNotification:userInfo];
//Perform background task
NSLog(#"Received a silent push..");
NSLog(#"userInfo: %#", userInfo.description);
_appDelegateVC.result.text = userInfo.description;
handler(UIBackgroundFetchResultNewData);
}
else{
//Normal Notification
[[IMFPushAppManager get] notificationReceived:userInfo];
NSLog(#"Received a normal notification.");
NSLog(#"userInfo: %#", userInfo.description);
_appDelegateVC.result.text = userInfo.description;
handler(UIBackgroundFetchResultNoData);
}
//Success
}
The contentAvailable value that is sent by the server for silent notifications is equal to 1.
Related
I am working on a chat app in react-native iOS. I want to do a badge increment on the main app icon when a notification is received, when the app is killed or force quit by the user. It works well when the app is in the background mode. But the didReceiveRemoteNotification method is not called when the app is inactive. Any idea on this? I added code inside the didReceiveRemoteNotification method of AppDelegate.
Added the following code set in AppDelegate file
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"APPDELEGATE: didReceiveRemoteNotification:fetchCompletionHandler %#", userInfo);
int badge = (int) application.applicationIconBadgeNumber;
if ( application.applicationState == UIApplicationStateInactive ) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
else if(application.applicationState == UIApplicationStateBackground) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
else if(application.applicationState == UIApplicationStateActive) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge+1];
}
completionHandler(UIBackgroundFetchResultNewData);
}
You need to create a UNNotificationServiceExtension to handle notifications when app is in background/killed.
It's a small application that will be executed on notification reception and has limited time to edit its content before presenting it to the user.
When you receive a notification in it's didReceive(_:withContentHandler:) delegate callback you can modify badge value of UNNotificationContent
In order to catch the incoming notification when the app is in the background or killed, use a UNNotificationServiceExtension in your project. The Info.plist for the UNNotificationServiceExtension (not the normal Info.plist for the main app; that one has normal things for the main app) might look something like
In the - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler of the UNNotificationServiceExtension, you can update the badge the following way:
self.bestAttemptContent = [request.content mutableCopy]; to get the request's content
self.bestAttemptContent.badge = <desired_integer_value> , where <desired_integer_value> would be the integer that you wish to put for the badge count.
self.contentHandler(self.bestAttemptContent); to complete the update of the content.
In many cases, the badge count may need to reflect a value (like number of unread chat messages) for a particular user. For that, you can use a shared user defaults. In fact NSUserDefaults supports the concept of app suite to allow such sharing. See Apple documentation for more details. In particular,
You can use this method when developing an app suite, to share preferences or other data among the apps, or when developing an app extension, to share preferences or other data between the extension and its containing app.
The argument and registration domains are shared between all instances of NSUserDefaults.
In a Constants.h file, have something to track individual counts for each user like
#define NOTIFICATIONS_UNREAD_SHARED [NSString stringWithFormat:#"notificationsUnread-%#",[mySharedDefaults objectForKey:USERNAME]]
and in your app, you would save the individual counts for each user, to the app suite's shared user defaults, with something like
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.yourCompany.yourAppname"];
if ([[NSUserDefaults standardUserDefaults] objectForKey:USERNAME]) {
mySharedDefaults setObject:[[NSUserDefaults standardUserDefaults] objectForKey:USERNAME] forKey:USERNAME];
[mySharedDefaults setObject:[NSNumber numberWithInteger:arrExistingRead.count] forKey:NOTIFICATIONS_READ_SHARED];
[mySharedDefaults setObject:[NSNumber numberWithInteger:([AppConstant sharedconstant].countObj.arrAllMessages.count - arrExistingRead.count)] forKey:NOTIFICATIONS_UNREAD_SHARED];
[mySharedDefaults synchronize];
}
Then in your UNNotificationServiceExtension, you would do something like
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.yourCompany.yourAppname"];
if ([mySharedDefaults objectForKey:NOTIFICATIONS_UNREAD_SHARED]) {
if ([mySharedDefaults objectForKey:USERNAME]) {
self.bestAttemptContent.badge = [NSNumber numberWithInt:[[mySharedDefaults objectForKey:NOTIFICATIONS_UNREAD_SHARED] intValue]+1];
} else { // username somehow not set; reset badge to 0
self.bestAttemptContent.badge = #0;
}
} else { // notifications unread count not found for this user; reset badge to 0
self.bestAttemptContent.badge = #0;
}
Troubleshooting
In case the extension doesn't appear to be receiving the push notifications, some things to verify:
Look at the build targets. Besides the main app, there should be one for the extension too.
In the settings for the main app, it should associate with the UNNotificationServiceExtension :
You need to set the badge field in the payload in the push notification.
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
You will have to do the calculation server side.
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]
}
I am working with a voip app using the Push Kit framework. I have some issues related to the delivery of the remote notification.
Issues
1) The notification messages send when the device was turned off is lost permenantly
2) After restarting the device, no push notification messages are recieved unless the application is started again
I have enabled voip over ip, background fetch, remote notification capabilities and checks any notification are available on
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary* payload = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (payload) {
// process the payload here
NSLog(#"There are some notifications are available for processing");
}
}
I have overrided following methods
//PushKit Notification Alerts methods
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
NSLog(#"voip token NULL");
return;
}
NSLog(#"PushCredentials: %#", credentials.token);
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type{
[self showLocalNotification:[[payload dictionaryPayload] valueForKey:#"data"]];
}
Its works fine when app is foreground and when its goes background.
Its also receives messages when user forcibly quits the application.
Testing platform OS version : IOS 8.1 and above Devices:iPhone 5C,iPhone 5S,iPhone 6, iPhone 6+
According to APNs Guides, messages are stored in APNs when target device is offline, and apple will only store the most recent message per app, it means all other messages will be discarded.
See the store-and-forward section here: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
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.
I am using notification in one of my app ,when app is active , notification is received , i process data and everything is fine , but I do not receive any notification when app is in background or killed.What is the issue can any one plz help me ?
Thank you!
Here is what I doing so far
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
tokenstring = [[NSString alloc] initWithFormat:#"%#",deviceToken];
tokenstring = [tokenstring stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
tokenstring = [[NSString alloc]initWithFormat:#"%#",[tokenstring stringByReplacingOccurrencesOfString:#" " withString:#""]];
NSLog(#"TokeinID:>> %#",tokenstring);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"didReceiveRemoteNotification: %#",userInfo);
AudioServicesPlaySystemSound(1002);
//Some code or logic
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"didFailToRegisterForRemoteNotificationsWithError: %#",err.description);
}
When you receive remote notifications, -application:didReceiveRemoteNotification: is only called when your app is in the foreground. If your app is in the background or terminated, then the OS may display an alert or play a sound (depending on the aps dictionary in the notification), but the delegate method is not called.
The remote notification received in the background will only passed to your application if it is launched with that notification's action button, and then you need to look at the launch options dictionary on -application:didFinishLaunchingWithOptions: to see the content of the notification.
If you're looking at new content fetching/remote notification background support with iOS7, check Will iOS launch my app into the background if it was force-quit by the user? and see if that helps, as there are very specific circumstances that those functions work in.
little code ..
When app is not running
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
is called ..
where u need to check for push notification
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(#"app recieved notification from remote%#",notification);
[self application:application didReceiveRemoteNotification:(NSDictionary*)notification];
}else{
}