My enterprise app is using Apple Push Notifications, and it works fine under most circumstances. What I would like to do is get the user information from a notification in a method other than the userDidRespondToPush.
If there is a notification waiting, the system puts a badge on the icon on the iPhone's home screen. If a user responds to the notification itself, the app will trigger userRespondsToPush. But if the user doesn't swipe the notification and starts the app normally, by tapping on the app's icon with a badge showing, I'd like to have the app respond as if the user did swipe the notification. That means I would need to get the userInfo in a method other than userDidRespondToPush so the app will know what information to show the user.
Push Notifications is pretty new to me, but I've had some pretty good luck getting it working. I just need this one little feature to work.
If your application supports iOS 10 and above, then you should be able to retrieve pending notifications using the UNUserNotificationCenter class.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
for (UNNotificationRequest *request in requests) {
NSDictionary *userInfo = request.content.userInfo;
NSLog(#"push user info: %#", userInfo);
// Handle the payload here.
}
}];
return YES;
}
I guess you want to know the app launched from RemoteNotifiication Or started normally from app icon.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
return YES;
}
if remote Notification exists, means app started from RemoteNotification, otherwise NO.
Here's a short answer to a similar question: how to get the userInfo in other delegate methods, other than didReceiveRemoteNotification. It depends on your delegate method, but basically you have to dig it out:
If you have notification: notification.request.content.userInfo. This is the case for userNotificationCenter(_:willPresent:withCompletionHandler:)
If you have response: response.notification.request.content.userInfo. This is the case for userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler
If you have userInfo: you've already got it.
You should either have notification, response or userInfo passed to you, depending on which delegate method is called.
Once you can get userInfo, you can do any logic you want in these delegate methods based on the dictionary your server sent you.
Related
I have a problem with push notifications in iOS, in a similar scenary to this and this and another one.
Also, this post resume all possible situations.
In my case:
app is NOT RUNNING
content-available:1
UIBackgroundModes contains 'remote-notifications' and 'fetch'
If the user force-quit the app and receives a push notification, then it could open app from alert or from icon.
When the user tap on the notification the app will be opened and the following method will be executed:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Handle for notifications when app is closed
if (launchOptions) {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
if (apsInfo) {
// handle notification
}
}
No problem up to here, I have the payload to doing something with that info (for example to fetch new data from server).
But if the user open the app from the icon I don't have any way to handle the payload (Although didFinishLaunchingWithOptions is execute, I don't have the aps info, according to docs here).
So, the question is, there are any way to solve that?
For example, I made the test with WhatsApp, and they handle that situation, (probably they are using VOIP notifications instead of Remote Notifications)
Regards
You should never assume that state has remained consistent between the time the notification has been delivered and the time the user has launched the app. Nor, even, that it is the same device. I'll frequently get a "Hey! Do something!" notification on my phone and, if my iPad is handy, respond to it on my nice big iPad screen.
Instead, you should round trip to the server and grab the most up to date state for that user at the time of app launch or activation.
I have done with all the cases except one while receiving Push Payload.
Here is my Implementation :
If the Application is in Background, inActive or Active State then we can receive Notification with this Method.
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
//Received Notification when the Application is Active, InActive or in Background State.
// NOTE : I am Handling below line of code with the Appropriate Conditions using Application States in my Code.
[self handleNotificationDataWithDictionary:dictionary updateUI:YES];
}
and If the Application is Suspended or Exited then we can receive the Notification Payload in didFinishLaunchingWithOptions Method but only in the case when user Taps on the Notification.
Here is the Implementation for receiving payload when app is exited or suspended and opened with the Tap of Push Notification from Home Screen or Lock Screen,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (launchOptions != nil)
{
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
[[[UIAlertView alloc] initWithTitle:#"Finish" message:#"Test" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil] show];
NSLog(#"Launched from push notification: %#", dictionary);
[self handleNotificationDataWithDictionary:dictionary updateUI:NO];
}
}
}
Now the Final Case is, When the Application is suspended and User didn't open the Application using the Notification Center rather opened the App by Tapping the Application Icon.
As I tested my code, I am not able to receive the Payload in this case. I googled a lot but found no solution on this Case.
As per Application docs, we can get Payload only in Background or InActive Mode when the App is not Active. Then how to implement it for Suspended State ?
I really need help on this, Please post your best Answers so that it might useful for others too.
Simply put - if user taps on App Icon your push is gone! No way to retrieve that info.
Official Documentation about this:
If the app icon is tapped on a device running iOS, the app calls the same method, but furnishes no information about the notification.
hris.to is absolutely right, if you want your custom notification panel inside your app, you have to build an API and then fetch once again from the server for the latest notifications.
I'm trying to integrate push notifications within my app. I've got handling remote notifications while the app is currently running working fine, however I'm trying to handle them when the app is not currently running using
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
however, it seems whenever I click the notification alert and it start up the app my notification payload is null.
I've used NSLog to log the payload and its showing that it is null.
Is there any reason it would be null? I know my notifications are setup right since they work within the app, but for some reason I cant figure this out. I've also logged the launchOptions and its showing null as well.
this is inside my didFinishLaunchingWithOptions method:
NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
NSLog(#"launch options: %#", launchOptions);
NSLog(#"payload: %#", notificationPayload);
I wrote a blog post about this a few years ago, and it's since changed in terms of where you set it up in Xcode.
But here's the blog post just in case, for some background information. http://runmad.com/blog/2010/06/debugging-executables-for-push-notifcations/
Now, in order to debug push notifications you need to edit the scheme.
You can change your target's launch settings in "Manage Scheme" to Wait for .app to be launched manually, which allows you debug by setting a breakpoint in application: didFinishLaunchingWithOptions: and sending the push notification to trigger the launch of your app.
application:didReceiveRemoteNotification: is a delegate method called when your app is currently active or comes to foreground.
It's important to test all 3 these scenarios thoroughly (from launch, from background, while active).
In the second method, you can check the app's state with
[application applicationState] == UIApplicationStateActive
and deal with the push notification accordingly.
If you want to see your payload information use following notification delegate method.And be sure that you have launch your app from notification center whenever you got notification, then only this method call.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"userInfo: %#", userInfo);
NSDictionary *dict=[userInfo objectForKey:#"aps"];
NSString *strPushMessege=[dict objectForKey:#"alert"];
NSLog(#"strPushMessege %#",strPushMessege);
}
When my app is on background and I receive a remote notification, two things can happen:
I tap on the push notification banner, my apps comes to foreground and didReceiveRemoteNotification is called.
I tap on my app icon from the springboard, my app comes to foreground and didReceiveRemoteNotification IS NOT called.
So, in the scenario 1, I can update my counter of unread messages inside the app in response to didReceiveRemoteNotification.
In the scenario 2, I can't.
How can I solve this using Quickblox?
As one possible variant:
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo) {
[self handleRemoteNotifications:userInfo];
}
// Override point for customization after application launch.
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[self handleRemoteNotifications:userInfo];
}
#pragma mark - Remote notifications handling
-(void)handleRemoteNotifications:(NSDictionary *)userInfo {
// do your stuff
}
#end
When app is not running, in didFinishLaunchingWithOptions: you can use this code for get push's payload:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSString *myKey = [userInfo objectForKey:#"myKeyFromPayload"];
}
Remember to set permission in plist
For the remote push you can use in your appdelegate:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
The issue is probably that application:didReceiveRemoteNotification: is not called if the app is not running. To quote Apple documentation:
This document is outdated
If the app is not running when a push notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary. The app does not call this method to handle that push notification. Instead, your implementation of the application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: method needs to get the push notification payload data and respond appropriately.
This is the new document
Use this method to process incoming remote notifications for your app. Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
You have to enable Remote Notifications in the Background Modes.
To do so, automatically: (Xcode5)
- Go to your Project settings -> Capabilities -> Background Modes
- Tick "Remote Notifications"
To do so, manually:
- Open your %appname%-Info.plist
- Right click and tick "Show Raw Keys/Values"
- Right click and choose "Add Row"
- Type in "UIBackgroundModes" (Key)
- The key will be created, and the type is an Array
- Add new item in the array with the value of "remote-notification" (Value) and press enter
- Now you have 1 item in your array called: "Item 0", if you had any other items in there, just add this item (remote-notification) to the array.
Be sure to use these methods frankWhite used :)
Hope this helps ;)
I'm setting up Apple push notification for my iOS app.
If several notification are received when the app is not running (or in background), how can all received notifications be taken into account when the app (re)starts ?
In iOS 5 the push notifications accumulate in the tray.
In application:didFinishLaunchingWithOptions:
use UIApplicationLaunchOptionsRemoteNotificationKey. This will give you the notification dictionary.
May be this can help you -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
}
There is no way of getting push notifications programmatically.
The only way to handle these notifications is to implement application:didFinishLaunchingWithOptions: which will contain data about the notification that the user tapped.
The good way to achieve what you want is to have a web service of your own that you call when your application enters foreground.