I have an app that can receive a push notification which is opened in a UIAlertView in the AppDelegate. The app will normally open to a tableview of items (if no push notification is present). Each item can be selected to view more detail about the item. How do I go about getting the detailed view to display with information from the push notification of an item? I saw this functionality in FaceBook Messenger where an incoming message launches the conversation from the specific user.
Thanks in advance
Push notifications can include embedded JSON, not just text, so you can put a small amount of command data into a push notification.
Here's some code that shows a message being passed in a push notification as well as an URL and a number that we only expect to see if the URL is there:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSString *message = [[userInfo objectForKey:#"aps"] objectForKey:#"alert"];
NSString *url = [userInfo objectForKey:#"url"];
if ([url length]) {
NSNumber *fooCount = [userInfo objectForKey:#"Foo"];
You can now do whatever your app wants to do with this data.
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.
Hello everyone,
I am trying how to implement pushnotification.For this i have read apple official document for push notification and also read raywenderlich blog and i understand the flow of pushnotication very well. I have created development and production certificate,profile and its working fine and push was successfully sent and receiving in -
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
*** display message in uialertview******
}
but my problem is how can i display push in my device like other push notification on top up side for both when my application is foreground and background too.
currently i am trying for IOS 7.0 and XCode Version 5.1.1 (5B1008)
Thanks In advance.
First of all check via these methods in App Delegate that if your registered successfully to APNS.
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
}
then in
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSDictionary *Notification = userInfo;
NSString *title = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"title"];
NSString *body = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"body"];
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
{
}
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive || [[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.userInfo = userInfo;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = body;
localNotification.fireDate = [NSDate date];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
If your application is in active state show UIAlertView. if its not you need to show a UILocalNotification.
When you are in Background mode then push notification will display as per your application notification settings from notification centre. you dont have to display ios will do that.
when you are in Foreground mode then notification will receive and -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo method will be called. so using this method you get userinfo. just NSLog userinfo dictionary and then you can create customview with label at top and animate it like ios default banner.
Hope this will help you.
As per Apple's note push/local notification will be display only when app is background mode. If notification is arrive at the time of app is on foreground/active then you need to manually manage it because iOS won't show a notification banner/alert That's default design.
I just put my logic here for manage notification when app in foreground mode:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
// check the application state for app is active or not.
if (application.applicationState == UIApplicationStateActive)
{
// Nothing to do if applicationState is Inactive, the iOS already displayed an alert view.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Receive a Remote Notification" message:[NSString stringWithFormat:#"Your App name received this notification while it was running:\n%#",[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]]delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
If you want to receive notification in top of the device like banner style then follow these steps.
First, you need to launch the 'Settings' app on your iOS device.
Once you're in, choose 'Notifications' from the list of options.
Here's a list of every app that supports push notifications. The ones at the top have been granted permission by you
You can also set the alert style. You can choose the banners that conveniently appear at the top of the screen, or full-on pop-ups that force you to take action before they go away. Or you can just choose 'None'.
For more detail check this link.
Hope you will get something from my answer.
I have an app where I have push notification.
What I have is I go to respective category when push is clicked (from the push notification list).
All is working perfectly, except when the app is killed.
If the app is minimized and push comes, if I click on push, it goes to respective category.
However if I forcefully kill the app and push comes and click on the push, it just open the app and no transition occurs.
Is this natural behavior in iPhone or I am doing something wrong?
In didReceiveRemoteNotification I go to specific category based on the data I received.
didReceiveRemoteNotification not call app will not run, that time push notification open app newly in device, you manually check if any notifications are bending in application:didFinishLaunchingWithOptions: try this for check bending notifications in app.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...............
...............
UILocalNotification *localNotif =[launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
NSLog(#"load notifiation *******");
isLoadNotification=YES;
}
return YES;
}
Below is what I used.
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
if (launchOptions != nil) {
NSMutableDictionary *dic = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey"];
NSMutableDictionary *dicItem = [dic objectForKey:#"aps"];
NSString *itemNotification = [dicItem objectForKey:#"alert"];
// do all transition here....
}else if (launchOptions == nil){
NSLog(#"launch ,,, nil");
}
...//code something
}
i'm not receiving newsstand notifications when the app is not running, here is what I have done.
The app has the proper plist keys 'UINewsstandApp = YES' and 'UIBackgroundModes = newsstand-content'.
In the app delegate I register for all notification types, and i receive my token from APNS, from the server side ( i am using a gem called Grocer ) i set up the dev certificate and send a regular push and it works.
if i send a newsstand push I receive it if the app is running on 'didReceiveRemoteNotification', but when the app is not running i get nothing in the notification center, which is mainly because 'Grocer' has the following payload
{"aps": {"content-available":1}} and can't add any other keys ( alert, badge, etc )
so I thought that I should not get anything in the notification center, I look for the 'UIApplicationLaunchOptionsRemoteNotificationKey' in the launch options, and then write a file to make sure that the app ran in the background, the file is never written as such
NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(remoteNotif)
{
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [cachePath stringByAppendingPathExtension:#"pushreceived.txt"];
[#"testing" writeToFile:filePath atomically:YES encoding:NSASCIIStringEncoding error:nil];
}
I have NKDontThrottleNewsstandContentNotifications set to true in my user defaults, and then I synchronize to make sure.
when the app is running, no matter how many times i send the push, I always get a callback on " didReceiveRemoteNotification ", with the proper "content-available"
if the app is closed or in the background, nothing happens.
Update:
I managed to change the gem that sends the notification payload, here is the dictionary it sends
{"aps"=>
{
"alert"=>"Hello iPhone!!",
"content-available"=>1,
"badge"=>1,
"sound"=>"default"
}
}
and here the userinfo dictionary I receive on my app ( while running )
{
aps = {
alert = "Hello iPhone!!";
badge = 1;
"content-available" = 1;
sound = default;
};
}
please note the quotation marks around content-available, does this mean that APNS parsed it as a custom key ?
To receive notifications when your application is running in the background, you need to add a applicationDidEnterBackgroud method to your main class. From the Apple documentation:
Applications might also find local notifications useful when they run in the background and some message, data, or other item arrives that might be of interest to the user. In this case, they should present the notification immediately using the UIApplication method presentLocalNotificationNow: (iOS gives an application a limited time to run in the background). Listing 2-2 illustrates how you might do this.
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIInvalidBackgroundTask, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIInvalidBackgroundTask;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
while ([application backgroundTimeRemaining] > 1.0) {
// Replace this code with your notification handling process
NSString *friend = [self checkForIncomingChat];
if (friend) {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif) {
localNotif.alertBody = [NSString stringWithFormat:
NSLocalizedString(#"%# has a message for you.", nil), friend];
localNotif.alertAction = NSLocalizedString(#"Read Message", nil);
localNotif.soundName = #"alarmsound.caf";
localNotif.applicationIconBadgeNumber = 1;
[application presentLocalNotificationNow:localNotif];
[localNotif release];
friend = nil;
break;
}
}
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIInvalidBackgroundTask;
});
}
Also note:
Because the only notification type supported for non-running applications is icon-badging, simply pass NSRemoteNotificationTypeBadge as the parameter of registerForRemoteNotificationTypes:.
Try these as a sanity check:
In Settings -> Newsstand, you have automatic content download as on for your app.
Make sure that you used [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeNewsstandContentAvailability] somehwere in your app.
Make sure that you have required background mode as 'newsstand-content' in your plist.
Run the app in the device, not in the simulator.
If you have done those correctly you should get a notification in didReceiveRemoteNotification even when your app is not running.
As the title says, when I first start up my app the dialog asking the user whether or not they want to receive push notifications doesn't appear. However if you go into settings the app appears in the push noticifications section, and the app DOES receive the push notification.
I'm using this to register for push, have I missed something out:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
I'm led to believe that if this is in didFinishLaunchingWithOptions that the prompt for the user would automatically appear?
Edit: I forgot to add that I do also have a didRegisterForRemoteNotificationsWithDeviceToken function in there too, to retain the token. As I say the notifications work in the sense that the user receives them, but the "do you want to receive them" popup never appears - which I would imagine are grounds for rejection by Apple.
Something like this is needed to retain the token:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" "
withString:#""];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:[NSString stringWithFormat:#"%#", token] forKey:#"DeviceToken"];
NSLog(#"APNs Device Token: %#", token);
}
See this thread also: didRegisterForRemoteNotificationsWithDeviceToken - Push Notifications