I'm developing a iOS app that manage Push Notifications. When a push comes up, the app badge is looking good, but where I'm having trouble is on the badges that appear inside the app. With inside the app i mean in the UITabBarItems that the app manages.
The app has a TabBarController where in two UITabBarItems a badge has to increment depending on wich Push Notification appeared. That is correctly handled in the server side, as I debuged and the push badge numbers comes ok. The thing is that the tab bar items are not updating ok.
Here's some part of my code:
This all happens inside de AppDelegate.m
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *user = [defaults stringForKey:#"id"];
if (user){
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"tabbar"];
self.window.rootViewController= viewController;
}
return YES;
}
And here's where I handle the push and update the badges in the uitabbaritem:
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Notify UAInbox to fetch any new messages if the notification
// contains a rich application page id.
if (application.applicationState != UIApplicationStateBackground) {
UA_LINFO(#"Received remote notification: %#", userInfo);
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshRequests" object:nil];
NSString* type = [userInfo objectForKey:#"type"];
if ([type isEqualToString:#"s"]){
[[[[(UITabBarController*)self.window.rootViewController viewControllers]
objectAtIndex: 2] tabBarItem] setBadgeValue:[[userInfo objectForKey:#"particularBadge"] stringValue]];
}else{
[[[[(UITabBarController*)self.window.rootViewController viewControllers]
objectAtIndex: 0] tabBarItem] setBadgeValue:[[userInfo objectForKey:#"particularBadge"] stringValue]];
}
}else{
// Notify UAPush that a push came in with the completion handler
[[UAPush shared] handleNotification:userInfo
applicationState:application.applicationState
fetchCompletionHandler:completionHandler];
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshRequests" object:nil];
[self clearNotifications];
}
When I debug it, the badge in [[userInfo objectForKey:#"particularBadge"] stringValue] is 1 for example, but when the code finished passing over there the uitabbaritem doesn't update. Sometimes it works ok, but others it doesn't and I can't figure out why.
When the app launches it asks if the user is logged..If not the self.window.rootviewController is a LoginViewController. I don't know if this information should be important.
Any help would be appreciated!
Related
I use APNs to send the notifications to my app. But my app does not work well when I did the following steps:
steps
swipe the app to force quit (app is not running, not in background mode ..)
send the notification from APNs
got the notification on my iPhone and I tapped the notification banner
app seemed to try to launch(showed the launch image), but launched fail (crash?)
my app can receive notification foreground and background.
Tap the notification banner in background then it can bring app to foreground then go to the view I wrote, everything works fine.
Except force quit the APP
here is my code in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MFSideMenuContainerViewController *container = [MFSideMenuContainerViewController
containerWithCenterViewController:[self navigationController]
leftMenuViewController:leftMenuViewController
rightMenuViewController:rightMenuViewController];
self.window.rootViewController = container;
[self.window makeKeyAndVisible];
UIMutableUserNotificationAction *acceptAction =
[[UIMutableUserNotificationAction alloc] init];
// Define an ID string to be passed back to your app when you handle the action
acceptAction.identifier = #"MARK_AS_READ_IDENTIFIER";
// Localized string displayed in the action button
acceptAction.title = NSLocalizedString(#"Mark as Read", nil);
// If you need to show UI, choose foreground
acceptAction.activationMode = UIUserNotificationActivationModeBackground;
// Destructive actions display in red
acceptAction.destructive = NO;
// Set whether the action requires the user to authenticate
acceptAction.authenticationRequired = NO;
// First create the category
UIMutableUserNotificationCategory *inviteCategory =
[[UIMutableUserNotificationCategory alloc] init];
// Identifier to include in your push payload and local notification
inviteCategory.identifier = #"actionCategory";
// Add the actions to the category and set the action context
[inviteCategory setActions:#[acceptAction]
forContext:UIUserNotificationActionContextDefault];
// Set the actions to present in a minimal context
[inviteCategory setActions:#[acceptAction]
forContext:UIUserNotificationActionContextMinimal];
NSSet *categories = [NSSet setWithObject:inviteCategory];
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert) categories:categories]];
// for calling didReceiveRemoteNotification when app first launch
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
[self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}
return YES;
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
//register to receive notifications
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"Device token: %#",deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Fail to get device token: %#", error);
}
// tap the backgraund banner button
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)newUserInfo completionHandler:(void (^)())completionHandler {
if ([identifier isEqualToString:#"MARK_AS_READ_IDENTIFIER"]) {
// when tapping the background banner's button will mark the notification status to read
[Functions updateComingNotificationToRead];
}
if (completionHandler) {
completionHandler();
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)newUserInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
//NSLog(#"Notification received: %# %#", newUserInfo,[newUserInfo objectForKey:#"aps"] );
userInfo = newUserInfo;
NSString *alertMessage = [[newUserInfo objectForKey:#"aps"] objectForKey:#"alert"];
UIApplicationState state = [application applicationState];
UIAlertView *alertView = nil;
// for background banner use
switch (state) {
case UIApplicationStateActive: // when app is alive, show alert to notify user
alertView = [[UIAlertView alloc]initWithTitle:NSLocalizedString(#"SmartHome",nil) message:NSLocalizedString(alertMessage,nil) delegate:self cancelButtonTitle:NSLocalizedString(#"Close",nil) otherButtonTitles:NSLocalizedString(#"Open",nil),NSLocalizedString(#"Mark as Read",nil), nil];
[alertView show];
break;
case UIApplicationStateBackground: // app is in background mode
// user tap the banner or tap the mark as read button, code will go here
[Functions addNotificationDataInDatabase:[newUserInfo objectForKey:#"uniqueID"] type:[newUserInfo objectForKey:#"deviceType"] event:[newUserInfo objectForKey:#"event"] time:[newUserInfo objectForKey:#"time"] read:#"0" description:alertMessage];
break;
case UIApplicationStateInactive: // tapping the banner
//NSLog(#"UIApplicationStateInactive");
// go to notification view
// because will go to the notification view detail, set status to read
[self gotoNotificationView:userInfo]; //uniqueID
break;
default:
break;
}
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
// Handle the received message
// Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
handler(UIBackgroundFetchResultNoData);
// send post notification for updating the badge, will get the notification in foreground
[[NSNotificationCenter defaultCenter] postNotificationName:#"APNsNotification" object:self userInfo:nil];
}
Does anyone have this problem before? Did I miss something?
Please help me!!
u can put alert and check launchOptions
if (launchOptions) {
if ([launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"]) {
[self application:self didReceiveRemoteNotification:[launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"] fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)newUserInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
NSString *str = [[userInfo objectForKey:#"aps"] objectForKey:#"alert"];
}
}
How to set badge for UIBarButtonItem from Appdelegate (whenever push notification comes) if UITabbarcontroller is not the rootviewcontroller ?
I have a LoginViewController and a PinViewController before UITabbarcontroller. I'm setting LoginViewController as rootviewcontroller if user has not logged in and PinViewController as rootviewcontroller if user has already logged in. But I found that we could set badge for UIBarButtonItem from Appdelegate only if the rootviewcontroller is UITabbarcontroller.
Can anyone help me with this?
You can manage it by Posting Notifications
// In App Delegate Class
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSNumber *count = [NSNumber numberWithInt:5]; // This is static...
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:count
forKey:#"count"];
application.applicationIconBadgeNumber = 0;
if (application.applicationState == UIApplicationStateActive)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"getPushNotification" object:dataDict];
}
}
In Controller where you want to update badge count on bar.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateBadgeCount:)
name:#"getPushNotification"
object:nil];
}
- (void)updateBadgeCount:(NSNotification *)note {
NSDictionary *theData = [note userInfo];
if (theData != nil) {
NSNumber *n = [theData objectForKey:#"count"];
// Do your stuff here...
}
}
Thanks.
I'm trying to figure out how I can examine the payload of a push notification in order to determine which view opens when a user opens the app from the notification. For example, if a notification says "x: test" view x would open when the notification is tapped and if the notification says "y: test" view y would open.
EDIT: I guess I should clarify the part I'm not sure about.
I have this in didFinishLaunchingWithOptions:
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification)
{
// check payload then load appropriate view controller
}
How would I check the payload for certain text in order to determine the appropriate view controller to load?
Here is my code from a past project. The notification shows up in device like this "Kostas: wants to add you as friend".
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
NSDictionary *remoteNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotif) {
NSString *name = [[NSString alloc] init];
NSString *message = [[NSString alloc] init];
// 'wants to add you as friend.'
NSString* alertValue = [[remoteNotif valueForKey:#"aps"] valueForKey:#"alert"];
NSMutableArray* parts = [NSMutableArray arrayWithArray:[alertValue componentsSeparatedByString:#": "]];
name = [parts objectAtIndex:0];
[parts removeObjectAtIndex:0];
message = [parts componentsJoinedByString:#": "];
if ([message isEqualToString:#": wants to add you as friend."]) {
UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;
// tabController.delegate = self;
tabController.selectedIndex = 1;
}
else{
UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;
// tabController.delegate = self;
tabController.selectedIndex = 2;
[self addMessageFromRemoteNotification:remoteNotif updateUI:NO];
}
Receiving a push notification is handled in two places in the app delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions when your app is launched from a push notification. In this case, your push notification data is contained within [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo when your app is running when receiving the notification. In this case, userInfo is your push notification data.
I recently use the Amazon SNS to push notification for my IOS app.
It works well, the only problem I have encountered is when I receive the notification , the badge number will not be updated, here is how I implement:
First I follow the example here
https://aws.amazon.com/articles/9156883257507082
, I extract only the SNS part that means I only alter the appdelegate in my app. Here is the example code from the tutorial.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
application.applicationIconBadgeNumber = 0;
NSString *msg = [NSString stringWithFormat:#"%#", userInfo];
NSLog(#"%#",msg);
[[Constants universalAlertsWithTitle:#"Push Notification Received" andMessage:msg] show];
}
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Register for push notification
application.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
if(launchOptions!=nil){
NSString *msg = [NSString stringWithFormat:#"%#", launchOptions];
NSLog(#"%#",msg);
[[Constants universalAlertsWithTitle:#"Push Notification Received" andMessage:msg] show];
}
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
Message_BoardViewController *boardViewController = [Message_BoardViewController new];
UINavigationController *navigationController = [UINavigationController new];
navigationController.navigationBar.translucent = NO;
[navigationController pushViewController:boardViewController animated:NO];
[boardViewController release];
self.window.rootViewController = navigationController;
[navigationController release];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
[self.window makeKeyAndVisible];
// Logging Control - Do NOT use logging for non-development builds.
#ifdef DEBUG
[AmazonLogger verboseLogging];
#else
[AmazonLogger turnLoggingOff];
#endif
[AmazonErrorHandler shouldNotThrowExceptions];
return YES;
}
As you can see, the badge number will always become 0, and also I found the JSON incoming notification from SNS is without badge field but only has alert field, didReceiveRemoteNotification is not call when the app is at background too.
So , how can I modify the code to update the badge? Thanks for kindly help.
Hi i have added push notification in my application and I want to view particular ViewControllers when the user tap the notification. In my app delegate m file I'm trying to get the register the device token to my server and from my server I'm using the php script to get the device token from server and I'm sending the notification.
The problem here I'm trying to view a particular view controller when the user taps on the notification its not working i have tried many different methods nothing had worked.
Here I'm view the popup like to send notification from the app when user trying to install application for the first time.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeNone)];
return YES;
}
- (void) clearNotifications {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
Here I'm storing the device to token to my server.
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
const char* data = [deviceToken bytes];
NSMutableString * token = [NSMutableString string];
for (int i = 0; i < [deviceToken length]; i++) {
[token appendFormat:#"%02.2hhX", data[i]];
}
NSString *urlString = [NSString stringWithFormat:#"url?token=%#",token];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSLog(#"token %#",urlString);
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSLog(#"request %# ",urlRequest);
NSData *urlData;
NSURLResponse *response;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil];
NSLog(#"data %#",urlData);
[self clearNotifications];
// NSLog(#"token ",sendUserToken);
}
Here I'm trying to view the particular method when user tap the notification.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
updatepoliticalViewController *ringingVC = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"updatepoliticalViewController"];
[self.window.rootViewController presentViewController:ringingVC animated:YES completion:NULL];
}
My particular view controller name is updatepoliticalViewController its a navigation view controller please tell me in this above code where I'm doing wrong how to resolve this issue.
Thanks
When the app is in foreground state it call
application:didReceiveRemoteNotification:
but if it's not and the app is launched, for example, by swiping the alert in notification center
application:didFinishLaunchingWithOptions:
is called with key.
The good way is to call
application:didReceiveRemoteNotification:
from
application:didFinishLaunchingWithOptions:
I believe this should help
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
[self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}
// YOUR CODE...
return YES;
}
// EXTENDED
Try get storyboard like that:
// Make sure the name match
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
Create your object from mainstoryboard:
updatepoliticalViewController *ringingVC = [mainstoryboard instantiateViewControllerWithIdentifier:#"updatepoliticalViewController"];
And try set new root view controller
[self.window setRootViewController: ringingVC];
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
NSLog(#"userInfo->%#",[userInfo objectForKey:#"aps"]);
}
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
NSLog(#"userInfo->%#",[userInfo objectForKey:#"aps"]);
}
}
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)
{
NSLog(#"userInfo->%#",[userInfo objectForKey:#"aps"]);
}
}
else{
//opened app without a push notification.
}
}