I've got a chat application where my server sends out push notifications when a new message is send. The problem I'm having is how can i take the user to the correct view? Im sending a channelID in the push notification but how can i retrieve it and take the user to the actual conversation?
I'm using this code to detect when a push notification was clicked
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//opened from a push notification when the app was on background
}
}
If you are sending channelID in push notification than you can retrieve channelID from userInfo dictionary.
As midhere said -
1) When application is running in background and When application is running in foreground
application:didReceiveRemoteNotification: method will called as below.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive)
{
//opened from a push notification when the app was on background
NSString channelID = [[userInfo objectForKey:#"aps"] objectForKey:#"channelID"];
NSLog(#"channelID->%#",channelID);
}
else if(application.applicationState == UIApplicationStateActive)
{
// a push notification when the app is running. So that you can display an alert and push in any view
NSString channelID = [[userInfo objectForKey:#"aps"] objectForKey:#"channelID"];
NSLog(#"channelID->%#",channelID);
}
}
2) When application is not launched (close) than application:didFinishedLaunchWithOptionsmethod will called.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (launchOptions != nil)
{
//opened from a push notification when the app is closed
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo != nil)
{
NSString channelID = [[userInfo objectForKey:#"aps"] objectForKey:#"channelID"];
NSLog(#"channelID->%#",channelID);
}
}
else{
//opened app without a push notification.
}
}
You will receive push notification on following scenarios.
When application is not launched : Notifications will be shown in notification center and application badge number will update as per notification badge detail. When user tap a notification from notification center, your chat application will be launched with notification info by invoking method application:didFinishedLaunchWithOptions. You just need check options dictionary for your remoteNotification data.
When application is running in foreground : You will receive push notifications in
application:didReceiveRemoteNotification: and you just need to check userInfo dictionary for your remote notification data.
When application is running in background : Notifications will be shown in notification center and application badge number will update as per notification badge detail. When user tap a notification from notification center, your chat application will come to foreground and you will receive user tapped notification in application:didReceiveRemoteNotification: and you just need to check userInfo dictionary for your remote notification data.
Once you get notification dictionary, you can access channelId and present respective chat screen based on received channelId.
Please refer apple doc for handling remote notifications
Related
I build and app that has Background Modes enabled, and the push notification payload that the app gets has "content-available" key.
This setup results in didReceiveRemoteNotification being called EVERY TIME the app gets a push notification, which means that if i get 3 push notifications while the app is in the background - the function will fire 3 times and the code inside it will be executed when the app will applicationDidBecomeActive
My biggest problem is that there is NO way to know if a user tapped the Push System Alert or tapped the app icon to bring the app from background, since regardless of the user's action, the didReceiveRemoteNotification will fire.
Is there a way to know for sure that the user tapped on the Sys alert?
and this: http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/
and other answers
don't seem to be helpful
For app is background push
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//opened from a push notification when the app was on background
}
}
For app is terminate state
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (launchOptions != nil) {
// Launched from push notification
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
}
}
I'm working on push notification flow but not getting exactly how to handle it. I need a simple explanation, when push notification comes, which delegate is called
When user tap on push notification label
When user tap on App icon when push notification comes
I'm unable to maintain to my app application state, for me the flow should be like:
When user tap on push notification label: It should open a particular viewcontroller
When user tap on App icon when push notification comes: It should open same viewcontroller from where app goes in background
How I can achieve this in Xcode 8.1/iOS 10.1.1?
Also I'm using background mode remote notification and background fetch.
In AppDelegate.m used it to check where user tap icon
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//Handle notification when the user click it while app is running in background or foreground.
if(application.applicationState == UIApplicationStateInactive) {
NSLog(#"Inactive - the user has tapped in the notification when app was closed or in background");
//do some tasks
}
else if (application.applicationState == UIApplicationStateBackground) {
NSLog(#"application Background - notification has arrived when app was in background");
}
else {
NSLog(#"application Active - notication has arrived while app was opened");
//do tasks
}
}
When a push notification sends from server a delegate call on app side but you have to register from app end by adding registerForPushNotifications.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
//Handle notification when the user click it while app is running in background or foreground.
//Where userinfo is a dict. It has the data sent from server
}
My push notification works properly in Normal case but i have problem with following case:
1) when my app remove from background and get notification & tap on app icon then i want to push view controller and display payload data in that view controller.
2 ) when my app in background and get notification & tap on app icon then i want to push view controller and display payload data in that view controller.
following is my userInfo
{
aps = {
alert = "Call from rohan panchal";
appointmentId = 220;
badge = 0;
"call_token" = "T1==cGFydG5lcl9pZD00NTI1ODY1MiZzaWc9MzM1MmM0M2E2MjkwN2JiYWMzNjgyNjk0MjFlZWMyNWEzNTZmZmM3MjpzZXNzaW9uX2lkPTJfTVg0ME5USTFPRFkxTW41LU1UUTNNREl3TVRBd01qVXdOWDV3WXpCRFMyWTRlR2xhUWpGdU1YbFpNamhvV0hoNFVHTi1VSDQmY3JlYXRlX3RpbWU9MTQ3MDIwMTAwMiZyb2xlPXB1Ymxpc2hlciZub25jZT0xNDcwMjAxMDAyLjUyMDM0NDAzNjQzMjMmZXhwaXJlX3RpbWU9MTQ3MDgwNTgwMg==";
doctorId = 238;
"doctor_country" = US;
"doctor_name" = "John smith";
patientId = 239;
"patient_country" = US;
"patient_name" = "Lottry patel";
sessionId = "2_MX40NTI1ODY1Mn5-MTQ3MDIwMTAwMjUwNX5wYzBDS2Y4eGlaQjFuMXlZMjhoWHh4UGN-UH4";
sound = default;
};
}
following my code.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// when i remove app from background & click on notification then following code run.
NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
if(notificationPayload)
{
NSLog(#"%#",notificationPayload);
WebViewController *DashBoard = [[WebViewController alloc]initWithNibName:#"WebViewController" bundle:nil];
self.navcntrl=[[UINavigationController alloc]initWithRootViewController:DashBoard];
}
else
{
DoctorMenuViewController *DoctorVC = [[DoctorMenuViewController alloc]initWithNibName:#"DoctorMenuViewController" bundle:nil];
self.navcntrl=[[UINavigationController alloc]initWithRootViewController:DoctorVC];
}
}
When I got notification then following method called.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"%#",userInfo);
WebViewController *DashBoard = [[WebViewController alloc]initWithNibName:#"WebViewController" bundle:nil];
[self.navcntrl pushViewController:DashBoard animated:YES];
}
Please help.Any help appreciated.
The push notification payload consists of:
alert - the alert string and actions
badge
sound
content-available
The key content-available is a new feature, and it is this key that makes silent push possible.
To enable, you also have to add remote-notifcation as your app UIBackgroundModes as described here.
This is what happens when content-available is in the payload:
If app is Suspended, the system will bring it into Background
If app was killed by user, nothing happens and app remains in Not Running
Read about app state changes.
A potential is pitfall:
You enable with content-available=1. But, it is WRONG to disable with content-available=0. To disable, you have to REMOVE the key in the payload.
plz use this
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if(application.applicationState == UIApplicationStateInactive)
{
NSLog(#"Inactive");
//do your things when you click on notification
}
else if (application.applicationState == UIApplicationStateBackground)
{
NSLog(#"Background");
}
else if (application.applicationState == UIApplicationStateActive)
{
NSLog(#"Active");
}
}
for more information plz read this link http://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/
application: didReceiveRemoteNotification:
is called when the OS receives a RemoteNotification and the app is running (in the background/suspended or in the foreground.)
and
application:(UIApplication *)application didFinishLaunchingWithOptions
is called when app is not running and you click on app icon.
1) when my app remove from background and get notification & tap on app icon -
TestViewController *testVC = your_test_vc;
UINavigationController *navVC = [[UINavigationController alloc]initWithRootViewController:testVC];
In TestViewController you can push your controller to show the payload data.
2) Whatever you wrote is correct.
Hope this will help you.
Apps have notification data delivered in a specific set of circumstances. If the user's interaction does not coincide with one of these, the data is not available. There are no exceptions.
the user taps a notification banner (or alert). It does not matter if the app was running or not.
the payload has the content-available field set to a true value, and iOS opts to deliver the notification.
Note: this answer does not explain how to invoke or handle any of the scenarios.
The field value from the userinfo is what you require then under
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (state == UIApplicationStateBackground || state == UIApplicationStateInactive)
{ //notification is received when your app is in background
//open the view controller you expected
}
else if(state == UIApplicationStateActive)
{
//notification is received when your app is in foreground
//do nothing
}
}
I have checked many threads and Apple Documentation for determining whether app is launched on tap of the notification.
I want to handle push notification only if user taps on notification.
I am not able to figure out reason of application:didReceiveRemoteNotification:fetchCompletionHandler: being called.
How can check if this method was called on tap of notification or direct from push when app is background.
Thanks.
Here is few steps for push Notification
1). When you app is killed, neither active nor in background. In that case didFinishLaunchingWithOptions will called when you receive any notification.
2). When your app is active or in background, in that case didReceiveRemoteNotification:fetchCompletionHandler** will called. You have to identify application state here as below.
if ( application.applicationState == UIApplicationStateActive ) {
// app was already in the foreground
}
else {
// app was just brought from background to foreground
}
- (void)application:(UIApplication *)app didReceiveRemoteNotification:(NSDictionary *)userInfo {
//No Need to store the push notification if it is in active or in closed state we can directly navigate to the screens
NSLog(#"notification didReceive method called");
if([app applicationState] == UIApplicationStateInactive) {
//If the application state was inactive, this means the user pressed an action button
//Handle the code after push notification received
}
else if ([app applicationState] == UIApplicationStateActive) {
//Application is in Active state handle the push notification here
}
}
I am not sure if this is possible, but I need to grab all of the push notification userinfo when the user opens up the App. I can get all of the push notification userinfo when the App is opened or in the background, but not when the App is completely closed. Any way around this? The code below is how I get the userInfo currently.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
id data = [userInfo objectForKey:#"data"];
NSLog(#"data%#",data);
}
Unfortunately, it's not currently possible client side with that method to query old notifications that have occurred while the app was completely closed. See this question: didReceiveRemoteNotification when in background.
A way around it is to keep track of which notifications you send from your server per user. When didReceiveRemoteNotification: is called, you can take that notification and compare it against the server's messages for the current user. If one of them matches, mark it some way on the server. That way, if there are messages sent when your app is backgrounded, you can query for messages that haven't been marked from the server and get all 'missed' notifications.
The method you are implementing cannot handle both cases. See the "Local and Push Notification Programming Guide":
If your app is frontmost, the application:didReceiveRemoteNotification: or application:didReceiveLocalNotification: method is called on its app delegate. If your app is not frontmost or not running, you handle the notifications by checking the options dictionary passed to the application:didFinishLaunchingWithOptions: of your app delegate...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Notifications
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo){
//open from notification message
}
return YES;
}
You can add this code to your AppDelegate's applicationWillEnterForeground method:
-(void)applicationWillEnterForeground:(UIApplication *)application {
// this method is called when staring an app that was closed / killed / never run before (after applicationDidFinishLaunchingWithOptions) and every time the app is reopened or change status from background to foreground (ex. returning from a mobile call or after the user switched to other app and then came back)
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
NSLog(#"AppDelegate-getDeliveredNotificationsWithCompletionHandler there were %lu notifications in notification center", (unsigned long)[notifications count]);
for (UNNotification* notification in notifications) {
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo) {
NSLog(#"Processed a notification in getDeliveredNotificationsWithCompletionHandler, with this info: %#", userInfo);
[self showPushNotificationInAlertController:userInfo]; // this is my method to display the notification in an UIAlertController
}
}
UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
}];
}
}
Remove this line from the method application didFinishLaunchingWithOptions: if you had included it there, because it clears the badge number and also all notifications in notifications center:
UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
This is currently working in iOS 12, hadn't had the chance to test it in earlier versions.