I have an iOS application which uses local notifications. When the app is running in the background or is active, I use the application didReceiveLocalNotification methods and that works great. But when the app is closed (not running in the background), I use the application didFinishLaunchingWithOptions method to control what happens when the notification is handled.
However, the problem I have is that the notification is always (null) in the didFinishLaunchingWithOptions method.
Here is my code:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Register the app for local notifcations.
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
}
// Setup the local notification check.
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
//UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"options" message:notification delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
//[alertView show];
// Check if a notifcation has been received.
if (notification) {
// Run the notifcation.
[self.myViewController run_notifcation:[notification.userInfo valueForKey:#"notification_id"]];
}
// Ensure the notifcation badge number is hidden.
application.applicationIconBadgeNumber = 0;
return YES;
}
Am I missing something here? I have asked the user for permission first and have the correct code to get the notification object. My app is built for iOS 9 and higher only.
Thanks for your time, Dan.
Display the value launchOptions in an alert view to see if there is any value.
If the value is not nil, then probably your UI code gets executed in the background thread.
Ensure all UI code is executed in the main thread as shown below:
dispatch_async(dispatch_get_main_queue(), ^{
//self doSomething (UI Code)
});
This is important when you use asynchronous calls in your app.
Implement your code in applicationWillTerminate rather than didFinishLaunchingWithOptions. Because when the app terminated then execute the applicationWillTerminate method.
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
Related
I'm building an app that asks the user for permission to post notifications when the user enables a switch. I'm using this code:
- (IBAction)mySwitchValueChanged:(id)sender {
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]; // ask the user for permission
}
if ([[UIApplication sharedApplication] respondsToSelector:#selector(currentUserNotificationSettings)]) { // Check it's iOS 8 and above
UIUserNotificationSettings *grantedSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
if (grantedSettings.types != UIUserNotificationTypeNone)
{
// Accepted
} else
{
[self.mySwitch setOn:NO]; // Declined
}
}
}
The desired behaviour is as follows:
User slides switch
Alert asks for permission
Code waits for user to decide
Either does whatever I code where I've put // accepted, or disables the switch.
The current behaviour makes the code run through at once, and doesn't wait for the user to decide. How can I change this to get the desired behaviour?
Thanks!
Note: This is workaround idea
Once you call this method :- [UIApplication sharedApplication] registerUserNotificationSettings and user grants push notification for the app, then didRegisterForRemoteNotificationsWithDeviceToken in AppDelegate get fired,
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
//call a notification when user granted Push Notifiaction
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PushNotificationSuccess"
object:self];
}
So what you have to do, you can call a NSNotification from the mentioned method, to update the UI accordingly.
- (void)updateUIOnNotification:(NSNotification *) notification
{
// Accepted
}
//Call the below method in your else part and remove the line
//[self.mySwitch setOn:NO];
-(void)Showalert{
UIAlertview*Temp=[[UIAlertview alloc]initWithTitle:#"Need Permission to Send Notifications" message:#"The App Wants The Permission to Work Properly!\nPermit The App in Notification settings"delegate:self cancelButtonTitle:#"Okay!" otherButtonTitles:nil];
[Temp show];
}
#pragma mark Alertview delegate method
- (void)alertViewCancel:(UIAlertView *)alertView{
//Remove the Below line From Else part of your code
[self.mySwitch setOn:NO];
}
I have a app to which i can send push notifications using pushbots. The user is able to receive the notification and on clicking it he/she can open the app. However the badge notification still shows that there is a notification. How would i set my notification badge to 0.
This is my appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Register for Remote Notifications
[Pushbots sharedInstanceWithAppId:#"5503e09a1d0ab1481f8b45a1"];
NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo) {
// Notification Message
NSString* notificationMsg = [userInfo valueForKey:#"alert"];
// Custom Field
NSString* title = [userInfo valueForKey:#"title"];
NSLog(#"Notification Msg is %# and Custom field title = %#", notificationMsg , title);
}
return YES;
}
-(void)onReceivePushNotification:(NSDictionary *) pushDict andPayload:(NSDictionary *)payload {
NSString* message = [pushDict valueForKey:#"alert"];
UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle:#"New Event !" message:message delegate:self cancelButtonTitle:#"Open" otherButtonTitles: #"I will check later",nil];
[alertMessage show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
Pushbots * pushbots = [Pushbots sharedInstance];
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Open"]) {
[pushbots OpenedNotification];
}
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
You can call this in your application :
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
Obviously this needs a little more work. If you're dealing with messages for example, you'd need to decrement the badge number by the number of messages read and make sure to not go below zero.
You can also use the "badge" key to modify the current badge through the notification payload itself.
for example use
{..., "badge" : "increment", ...}
or
{...,"badge" : 3, ...}
The first one would be the most frequent version i'm guessing.
But if your app is fairly simple, then just call this and your badge will be set to zero.
I'd advise you to update your pushbots lib to 1.1 and use the following method which will clear the badge locally and on the server:
[[Pushbots sharedInstance] clearBadgeCount];
For Swift 3
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
Pushbots.sharedInstance().clearBadgeCount()
}
func applicationWillEnterForeground(application: UIApplication)
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
Pushbots.sharedInstance().clearBadgeCount()
}
Objective C
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
[[Pushbots sharedInstance] clearBadgeCount];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
[[Pushbots sharedInstance] clearBadgeCount];
}
I am using local notification for alarm system but I am facing some problem while handling local notification, When i clicked on alarm notification (When app is closed) its launches app but the problem is it should go to didFinishLaunchingWithOptions function but it's not going inside any of the function in appDelegate (I used breakpoints to check).
I'm using story board with navigation controller, I want to open a specific view controller on notification click when app is closed.
but when I'm launching that app normally it's going inside didFinishLaunchingWithOptions function.
Please suggest.
Any help would be appreciated.
main.m
#import "DEMOAppDelegate.h"
int main(int argc, char * argv[])
{
#autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([DEMOAppDelegate class]));
}
}
DEMOAppDelegate.m
#import "DEMOAppDelegate.h"
#implementation DEMOAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotif = [launchOptions objectForKey: UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif)
{
NSLog(#"Recieved Notification %#",localNotif);
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:notification.alertAction message:notification.alertBody delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
#end
It's not possible, when your app is not running notification it will not react on notification directly.
didFinishLaunchingWithOptions will contain information about notification only when user opened your app through this notifcation. If he cancels it and opens your app through dashboard icon you are not gonna see this in this method.
Unfortunatelly if you need to react on all notification that happened from last time the user opened the app, only way is to build your own tracking logic and get all events that were in the past based on time.
Also there is no way to even get a list of notification you scheduled for your app, so usually it is a good idea to build in time-based event logic and use notification on top of it, but all the logic happens on your own time-based code. This way even if user disable notifications your critical logic will work.
When the application is running in background you will get notification through application:didReceiveRemoteNotification. You can gather those notifications inside your app, and process them on applicationDidBecomeActive if you want to do anything specific inside your application for them after user comes back to the app from background.
In my app I am using uilocalnotifications. Every thing is ok but one thing. I need to show notifications's alertbody. If app is in foreground state it's fine, but if app is at background state and notification occurs, when i tap on that didReceiveLocalNotification doesn't get called. Obviously didFinishLaunchingWithOptions is also don't called at that time. So what should i do to handle the notification. I am using ios7 and xcode5. Thanks very much in advance if you could help me.
For an app which is not in the foreground, the local notification can subsequently be found in the
-applicationDidFinishLaunchingWithOptions method
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
//Handle local notification here.
}
You can read Apple's documentation for handling notifications here.
If the app is currently in memory, you can check it's state in the following way:
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif
{
if (app.applicationState == UIApplicationStateInactive )
{
NSLog(#"app not running");
}
else if(app.applicationState == UIApplicationStateActive )
{
NSLog(#"app running");
}
}
if application is closed and notification is raised then for that you have to write below code in appdidfinishlaunching method
// Handle launching from a notification
UILocalNotification *objLocalNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (objLocalNotif)
{
NSLog(#"At the time of launching Recieved Notification %#",objLocalNotif);
//Do your stuff here
}
If application is in background and when any local notification is raised the following method of app delegate get called.
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
// Handle the notificaton when the app is running
NSLog(#"Recieved Notification %#",notif);
//do your stuff here
}
Write your code in the below method
- (void)applicationWillEnterForeground:(UIApplication *)application
it will be called when you open your application again which has not been terminated fully but still running in background
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];'
I added the above code to didfinishLaunchingWithOptions but when a user taps a notification in his notification center and enters my app the notification does not gets cleared.
Edit:
I also tried adding this to my code:
You Also need to increment then decrement the badge in your
application:didReceiveRemoteNotification: method if you are trying
to clear the message from the message centre so that when a user
enters you app from pressing a notification the message centre will
also clear, ie:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
as describes here: iOS application: how to clear notifications? but the notification still won't clear from the notification center
I just Added a Badge number manually to my application and pasted
- (void)applicationDidBecomeActive:(UIApplication *)application
{
application.applicationIconBadgeNumber = 0;
}
To my AppDelegate. For me this works like a charm.
Note that didfinishLaunchingWithOptions and applicationDidBecomeActive are not the same as Mouhammad Lamaa explained. If you paste this to your AppDelegate and tap the notification in notification center it should disapper. If it does not your App maybe creates a new Notification after becoming active?
add this code
- (void)applicationDidBecomeActive:(UIApplication *)application
{
application.applicationIconBadgeNumber = 0;
}
the didfinishlaunchingwithoptions launched at the initial launch of your app. if your app the running in the background, didfinishlaunchingwithoptions will not be launched.
When the user open application from notification action - it launches with
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *remoteNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotif) {
//handle remote notification
}
....
}
But when the app was in background it calls
- application:didReceiveRemoteNotification:
Also method [[UIApplication sharedApplication] cancelAllLocalNotifications]; cancel registered LOCAL notifications only. Push notifications can't be canceled - they delivered immediately and executed only once.