How to implement interactive notifications ios8 - objective-c

I'm creating a timed todo list app in which users can start a timer from a lock screen notification by swiping to reveal a start button. This is a new feature shown in iOS 8 but there is little documentation showing how to implement this feature.
Can anyone show how I would go about setting up the 'start' action and the block of code which runs when this is pressed? If the app were closed would this feature still work?

#Shubhendu thanks for the link. For those of you who don't want to have to sit through the video, here's a quick recap of what you need to do in order to include interactive notifications in you application.
Define all the actions that the user may execute from your app's notifications. These actions are created using the UIMutableUserNotificationAction class.
UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];
action.identifier = #"ACTION_ID"; // The id passed when the user selects the action
action.title = NSLocalizedString(#"Title",nil); // The title displayed for the action
action.activationMode = UIUserNotificationActivationModeBackground; // Choose whether the application is launched in foreground when the action is clicked
action.destructive = NO; // If YES, then the action is red
action.authenticationRequired = NO; // Whether the user must authenticate to execute the action
Place these actions into categories. Each category defines a group of actions that a user may execute from a notification. These categories are created using UIMutableUserNotificationCategory.
UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
category.identifier = #"CATEGORY_ID"; // Identifier passed in the payload
[category setActions:#[action] forContext:UIUserNotificationActionContextDefault]; // The context determines the number of actions presented (see documentation)
Register the categories in the settings. Note that registering the categories doesn't replace asking for user permission to send remote notifications,using [[UIApplication sharedApplication] registerForRemoteNotifications]
NSSet *categories = [NSSet setWithObjects:category, nil];
NSUInteger types = UIUserNotificationTypeNone; // Add badge, sound, or alerts here
UIUserNotificationSettings *settings = [UIUSerNotificationSettings settingsForTypes:types categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
Send the identifier of the category in the notification payload.
{
"aps":{
"alert":"Here's a notification",
...
"category":"CATEGORY_ID"
}
}
Handle user actions in the app delegate by implementing the UIApplicationDelegate protocol methods:
application:handleActionWithIdentifier:forRemoteNotification:completionHandler: for remote notifications
application:handleActionWithIdentifier:forLocalNotification:completionHandler: for local notifications

STEP 1:
NSString * const NotificationCategoryIdent = #"ACTIONABLE";
NSString * const NotificationActionOneIdent = #"ACTION_ONE";
NSString * const NotificationActionTwoIdent = #"ACTION_TWO";
- (void)registerForNotification {
UIMutableUserNotificationAction *action1;
action1 = [[UIMutableUserNotificationAction alloc] init];
[action1 setActivationMode:UIUserNotificationActivationModeBackground];
[action1 setTitle:#"Action 1"];
[action1 setIdentifier:NotificationActionOneIdent];
[action1 setDestructive:NO];
[action1 setAuthenticationRequired:NO];
UIMutableUserNotificationAction *action2;
action2 = [[UIMutableUserNotificationAction alloc] init];
[action2 setActivationMode:UIUserNotificationActivationModeBackground];
[action2 setTitle:#"Action 2"];
[action2 setIdentifier:NotificationActionTwoIdent];
[action2 setDestructive:NO];
[action2 setAuthenticationRequired:NO];
UIMutableUserNotificationCategory *actionCategory;
actionCategory = [[UIMutableUserNotificationCategory alloc] init];
[actionCategory setIdentifier:NotificationCategoryIdent];
[actionCategory setActions:#[action1, action2]
forContext:UIUserNotificationActionContextDefault];
NSSet *categories = [NSSet setWithObject:actionCategory];
UIUserNotificationType types = (UIUserNotificationTypeAlert|
UIUserNotificationTypeSound|
UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings;
settings = [UIUserNotificationSettings settingsForTypes:types
categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
STEP 2:
To send this type of notification simply add the category to the payload.
{
"aps" : {
"alert" : "Pull down to interact.",
"category" : "ACTIONABLE"
}
}
STEP 3:
Use this method
application:handleActionWithIdentifier:forRemoteNotification:completionHand
ler:
[application:handleActionWithIdentifier:forLocalNotification:completionHandler:
-> For LOCAL Notification]
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
if ([identifier isEqualToString:NotificationActionOneIdent]) {
NSLog(#"You chose action 1.");
}
else if ([identifier isEqualToString:NotificationActionTwoIdent]) {
NSLog(#"You chose action 2.");
}
if (completionHandler) {
completionHandler();
}
}
1.Refer link: Obj C tutorial
2.Swift Code Tutorial here

In order to know more about interactive notifications- a new feature in iOS 8 go to the below link
https://developer.apple.com/videos/wwdc/2014/
and then go to the section "What's New in iOS Notifications"

With iOS 8 came an exciting new API for creating interactive notifications. These allow you to provide additional functionality to your users outside of your application.
Let’s get started. There are 3 new classes in iOS 8 which are needed: UIUserNotificationSettings, UIUserNotificationCategory, UIUserNotificationAction and their mutable counterparts.
Instead of simply registering for notification types (sounds, banners, alerts) you can now also register for custom notification categories and actions. Categories describe a custom type of notification that your application sends and contains actions that a user can perform in response. For example you receive a notification that someone followed you on a social network. In response you might want to follow them back or ignore.
NSString * const NotificationCategoryIdent = #"ACTIONABLE";
NSString * const NotificationActionOneIdent = #"ACTION_ONE";
NSString * const NotificationActionTwoIdent = #"ACTION_TWO";
- (void)registerForNotification {
UIMutableUserNotificationAction *action1;
action1 = [[UIMutableUserNotificationAction alloc] init];
[action1 setActivationMode:UIUserNotificationActivationModeBackground];
[action1 setTitle:#"Action 1"];
[action1 setIdentifier:NotificationActionOneIdent];
[action1 setDestructive:NO];
[action1 setAuthenticationRequired:NO];
UIMutableUserNotificationAction *action2;
action2 = [[UIMutableUserNotificationAction alloc] init];
[action2 setActivationMode:UIUserNotificationActivationModeBackground];
[action2 setTitle:#"Action 2"];
[action2 setIdentifier:NotificationActionTwoIdent];
[action2 setDestructive:NO];
[action2 setAuthenticationRequired:NO];
UIMutableUserNotificationCategory *actionCategory;
actionCategory = [[UIMutableUserNotificationCategory alloc] init];
[actionCategory setIdentifier:NotificationCategoryIdent];
[actionCategory setActions:#[action1, action2]
forContext:UIUserNotificationActionContextDefault];
NSSet *categories = [NSSet setWithObject:actionCategory];
UIUserNotificationType types = (UIUserNotificationTypeAlert|
UIUserNotificationTypeSound|
UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings;
settings = [UIUserNotificationSettings settingsForTypes:types
categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
//JSON payload:
{
"aps" : {
"alert" : "Pull down to interact.",
"category" : "ACTIONABLE"
}
}
Now to handle the actions the user selects, there are 2 new methods on the UIApplicationDelegate protocol:\
application:handleActionWithIdentifier:forLocalNotification:completionHandler:
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
These methods will get called, in the background, when the user selects an action from your push notification.
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
if ([identifier isEqualToString:NotificationActionOneIdent]) {
NSLog(#"You chose action 1.");
}
else if ([identifier isEqualToString:NotificationActionTwoIdent]) {
NSLog(#"You chose action 2.");
}
if (completionHandler) {
completionHandler();
}
}

For ios10 Actionable push use this
UNAuthorizationOptions authOptions =
UNAuthorizationOptionAlert
| UNAuthorizationOptionSound
| UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
}
];
UNNotificationAction *ok = [UNNotificationAction actionWithIdentifier:#"OK"
title:NSLocalizedString(#"OK", nil)
options:UNNotificationActionOptionForeground];
UNNotificationAction *cancel = [UNNotificationAction actionWithIdentifier:#"CANCEL"
title:NSLocalizedString(#"CANCEL", nil)
options:UNNotificationActionOptionForeground];
NSArray *buttons = #[ ok, cancel ];
// create a category for message failed
UNNotificationCategory *buttonsAction = [UNNotificationCategory categoryWithIdentifier:#"ACTION_BUTTON"
actions:buttons
intentIdentifiers:#[]
options:UNNotificationCategoryOptionCustomDismissAction];
NSSet *categories = [NSSet setWithObjects:buttonsAction, nil];
// registration
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories];

Related

iOS8 Touch ID & Passcode

i using this code in iOS 8 for security and uses touch ID
- (IBAction)authenticateButtonTapped{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Authenticate using your finger\r Scan Your Finger Now";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL succes, NSError *error) {
if (succes) {
[self showMessage:#"Authentication is successful" withTitle:#"Success"];
NSLog(#"User authenticated");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
[self showMessage:#"Authentication is failed" withTitle:#"Error"];
NSLog(#"Authentication Failed");
break;
case LAErrorUserCancel:
[self showMessage:#"You clicked on Cancel" withTitle:#"Error"];
NSLog(#"User pressed Cancel button");
break;
case LAErrorUserFallback:
[self showMessage:#"You clicked on \"Enter Password\"" withTitle:#"Error"];
NSLog(#"User pressed \"Enter Password\"");
[self copyMatchingAsync];
break;
default:
[self showMessage:#"Touch ID is not configured" withTitle:#"Error"];
NSLog(#"Touch ID is not configured");
break;
}
NSLog(#"Authentication Fails");
}
}];
} else {
NSLog(#"Can not evaluate Touch ID");
[self showMessage:#"Can not evaluate TouchID" withTitle:#"Error"];
}
}
after for use the passcode system i copy this code from apple example
- (void)copyMatchingAsync
{
NSDictionary *query = #{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: #"SampleService",
(__bridge id)kSecReturnData: #YES,
(__bridge id)kSecUseOperationPrompt: NSLocalizedString(#"AUTHENTICATE_TO_ACCESS_SERVICE_PASSWORD", nil)
};
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CFTypeRef dataTypeRef = NULL;
NSString *msg;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &dataTypeRef);
if (status == errSecSuccess)
{
NSData *resultData = ( __bridge_transfer NSData *)dataTypeRef;
NSString * result = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
msg = [NSString stringWithFormat:NSLocalizedString(#"RESULT", nil), result];
} else {
}
});
}
-(void) showMessage:(NSString*)message withTitle:(NSString *)title
{
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
its work great and rapid for fingerprint but the passcode system can't show and dosen't work. and i received "ERROR_ITEM_NOT_FOUND" = "error item not found";
this apple link https://developer.apple.com/library/ios/samplecode/KeychainTouchID/Introduction/Intro.html
but i can't good understand
Sorry to tell you but you can't do that.
You are mixing access control with keychain access, You don't have access to the user passcode.
using SecItemCopyMatching is possible if you added a resource with SecItemAdd using the same attributes (the contents of "query")
"ERROR_ITEM_NOT_FOUND" = "error item not found" show no item in keychain.
I also saw the Apple sample code "KeychainTouchID" as you said above.
iOS8's new feature make the developer can use the iPhone user's passcode & Touch ID for authentication.
You have to "Add Item" firstly, and then call "Query for Item".
If you want more convenient solution, maybe you can use SmileTouchID.
It is a library for integrate Touch ID & Passcode to iOS App conveniently that even support for iOS7 and the device that cannot support Touch ID.
You just need a few line of code and get what you want.
if ([SmileAuthenticator hasPassword]) {
[SmileAuthenticator sharedInstance].securityType = INPUT_TOUCHID;
[[SmileAuthenticator sharedInstance] presentAuthViewController];
}

presentRequestsDialogModallyWithSession does not work, but gives good result

When I use the webdialog for a friendrequest, everything is going fine, except no request or anything is made.
The code:
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
facebookFriend.id, #"to",
nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:FBSession.activeSession
message:NSLocalizedString(#"FB_FRIEND_INVITE_MESSAGE", #"Facebook friend invite message")
title:NSLocalizedString(#"FB_FRIEND_INVITE_TITLE", #"Facebook friend invite title")
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
}];
This is the result I get:
fbconnect://success?request=xxxxxxxxxxxx&to%5B0%5D=xxxxxxxx
How can I debug what is going wrong?
Thanks in advance.
Ruud
For SDK 3.2 or above we have a facility to use FBWebDialogs class that will help us to show a popup along with the friend list and pick one or more from list to send invitation.
Lets do it step by step:
1) Download and setup SDK 3.2 or above.
2) First setup your application on facebook by following this url.
3) Then use the attached code.
Sample Code: (It generates invite friend request)
-(void)inviteFriends
{
if ([[FBSession activeSession] isOpen])
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}
];
}
else
{
/*
* open a new session with publish permission
*/
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObject:#"publish_stream"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
if (!error && status == FBSessionStateOpen)
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}];
}
else
{
[self requestFailedWithError:error];
}
}];
}
}
and here are the helper functions that calls delegates function OnFBSuccess and OnFBFailed.
- (void)requestSucceeded
{
NSLog(#"requestSucceeded");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBSuccess");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
- (void)requestFailedWithError:(NSError *)error
{
NSLog(#"requestFailed");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBFailed:");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback setArgument:&error atIndex:2];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
So the class taht calls method InviteFriend MUST have these functions:
-(void)OnFBSuccess
{
CCLOG(#"successful");
// do stuff here
[login release];
}
-(void)OnFBFailed:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
// do stuff here
[login release];
}
Recommended Reads:
Send Invitation via Facebook
API Permissions
An Example
NOTE:
1) Don't forget to setup Facebook application ID in plist.
2) Don't forget to adjust AppDelegate to handle urls.
Partial snippet taken from above link in point 2:
/*
* If we have a valid session at the time of openURL call, we handle
* Facebook transitions by passing the url argument to handleOpenURL
*/
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
return [FBSession.activeSession handleOpenURL:url];
}
Hope it helps!
EDIT
Here:
declaration for fbDelegate is:
#property (nonatomic, assign) id <FBLoginDelegate> fbDelegate;
#protocol FBLoginDelegate <NSObject>
#required
-(void) OnFBSuccess;
-(void) OnFBFailed : (NSError *)error;
#end
and this is how you can consume this code:
FBLoginHandler *login = [[FBLoginHandler alloc] initWithDelegate:self]; // here 'self' is the fbDelegate you have asked about
[login inviteFriends];
I think your application is not enable for Android and for web . And you are trying to get notification on web or on Android device.
Points : For getting notification on Android or on web you have to enable your app for Android and web too .
To Enable Android and Web on your App : GoTo your App > Setting > Click on + Add platform add enter necessary information and Save .
Lets Enjoy Notification . :-)

Is it possible to update the local notification in iPhone

I have added a local notification programmatically like below:
UILocalNotification *eventLocalNotification=[[UILocalNotification alloc]init];
eventLocalNotification.fireDate=myDate;
eventLocalNotification.timeZone=[NSTimeZone defaultTimeZone];
eventLocalNotification.alertBody=#"My notification";
eventLocalNotification.soundName=UILocalNotificationDefaultSoundName;
Can I change the firingDate, timeZone, alertBody, or any other property?
After searching a lot over internet, I got a thing that we can't edit a UILocal Notification once added. But sure there is another way that I have found.
Get all the Local notification of your device.
Search the respective local notification
Cancel that notification
Create a New one
Below is the method to add the notification.
-(void)setLocalNotification
{
UILocalNotification *eventLocalNotification = [[UILocalNotification alloc]init];
eventLocalNotification.fireDate = //set firing Date of NSDate type
eventLocalNotification.timeZone = [NSTimeZone defaultTimeZone];
eventLocalNotification.alertBody = [NSString stringWithFormat:#"An event has arrived\n Event Name: %#",notificationName.Text];
eventLocalNotification.soundName = UILocalNotificationDefaultSoundName;
if ([repeat isEqualToString:#"Once"]){
eventLocalNotification.repeatInterval = 0;
}else if ([repeat isEqualToString:#"Daily"]){
eventLocalNotification.repeatInterval = NSDayCalendarUnit;
}else if ([repeat isEqualToString:#"Weekly"]){
eventLocalNotification.repeatInterval = NSWeekCalendarUnit;
}else if ([repeat isEqualToString:#"Monthly"]){
eventLocalNotification.repeatInterval = NSMonthCalendarUnit;
}else if ([repeat isEqualToString:#"Yearly"]){
eventLocalNotification.repeatInterval = NSYearCalendarUnit;
}
NSDictionary *info = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%#",notificationName.text] forKey:#"name"];
eventLocalNotification.userInfo = info;
NSLog(#"notification userInfo gets name : %#",[info objectForKey:#"name"]);
[[UIApplication sharedApplication] scheduleLocalNotification:eventLocalNotification];
NSLog(#"Notification created");
}
Below is the function to cancel the notification
-(void)cancelLocalNotification
{
UILocalNotification * notificationToCancel=nil;
for(UILocalNotification * aNotif in [[UIApplication sharedApplication] scheduledLocalNotifications])
{
NSLog(#"%#",[aNotif.userInfo objectForKey:#"name"]);
if([[aNotif.userInfo objectForKey:#"name"] isEqualToString:notificationName ])
{
notificationToCancel = aNotif;
[[UIApplication sharedApplication] cancelLocalNotification:notificationToCancel];
NSLog(#"Notification Cancelled");
break;
}
}
}
Hope you will get benefit from it. Best of Luck
To set your date and time, you will have to use NSDateComponents and instantiate NSDate twice. One for current date and another will be your desirable date. Than set desirable NSDate's instance to fireDate of UILocalNotification's object.
eventLocalNotification.fireDate = desiredDate;
for timezone, keep it to default the way you did.
eventLocalNotification.timeZone = [NSTimeZone defaultTimeZone];
Alert body could be anything, just put your context.
eventLocalNotification.alertBody = #"DESIRED CONTEXT";

Game Center Invitation Handler for when someone accepts and invite in cocos2D

I have it working where if two players are in the same scene you can invite them and it'll add them to the players list when they accept.
What I don't have working and I'm not sure how to do is make the right scene load up when one player isn't in the app and the other player is in the app sending an invite request from one of the CCScenes.
I don't know if there is a way to do this or if it's the best way. My thoughts on this is that I want to send the name of the scene the person inviting a player is in to the person they are inviting through the invite handler. I'd assume I would have to send info somehow to the application didFinishLaunchingWithOptions if they weren't in the app but if they were I'd have it handler that elsewhere. I've been searching everywhere and haven't come across anything. If you guys know how do this or a better way of doing it I would be greatly appreciative for your help.
Here is the code I use for the invite handler:
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
UIViewController *topLevelViewController = self.presentingViewController;
bool isInviter = NO;
if (acceptedInvite) {
isInviter = NO;
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite] autorelease];
mmvc.matchmakerDelegate = self;
if ([topLevelViewController modalViewController] != nil)
[topLevelViewController dismissModalViewControllerAnimated:NO];
[topLevelViewController presentModalViewController:mmvc animated:YES];
} else if (playersToInvite) {
isInviter = NO;
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = playersToInvite;
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
mmvc.matchmakerDelegate = self;
if ([topLevelViewController modalViewController] != nil)
[topLevelViewController dismissModalViewControllerAnimated:NO];
[topLevelViewController presentModalViewController:mmvc animated:YES];
}
};

Delete a particular local notification

I am developing an iPhone alarm app based on local notifications.
On deleting an alarm, the related local notification should get cancelled. But how can I determine exactly which object from the array of local notifications is to be cancelled?
I am aware of [[UIApplication sharedApplication] cancelLocalNotification:notification] method but how can I get this 'notification' to cancel it?
You can save a unique value for key in your local notification's userinfo.
Get all local notification, loop through the array and delete the particular notification.
Code as follows,
OBJ-C:
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
SWIFT:
var app:UIApplication = UIApplication.sharedApplication()
for oneEvent in app.scheduledLocalNotifications {
var notification = oneEvent as UILocalNotification
let userInfoCurrent = notification.userInfo! as [String:AnyObject]
let uid = userInfoCurrent["uid"]! as String
if uid == uidtodelete {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
UserNotification:
If you use UserNotification (iOS 10+), just follow this steps:
When creating the UserNotification content, add an unique identifier
Remove specific pending notification using removePendingNotificationRequests(withIdentifiers:)
Remove specific delivered notification using removeDeliveredNotifications(withIdentifiers:)
For more info, UNUserNotificationCenter
Other Option:
First of All, when you create local notification, you can store it in user defaults for future use, Local notification object can not be stored directly in user defaults, This object needs to be converted into NSData object first, and then NSData can be stored into User defaults. Below is code for that:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:localNotif];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[NSString stringWithFormat:#"%d",indexPath.row]];
After you have stored and scheduled local notification, In future, requirement may arise that you need to cancel any of notification that you created earlier, So you can retrieve it from User defaults.
NSData *data= [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"%d",UniqueKey]];
UILocalNotification *localNotif = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"Remove localnotification are %#", localNotif);
[[UIApplication sharedApplication] cancelLocalNotification:localNotif];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:#"%d",UniqueKey]];
Hope This helps
Here is what i do.
When creating your notification do this:
// Create the notification
UILocalNotification *notification = [[UILocalNotification alloc] init] ;
notification.fireDate = alertDate;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertAction = NSLocalizedString(#"Start", #"Start");
notification.alertBody = **notificationTitle**;
notification.repeatInterval= NSMinuteCalendarUnit;
notification.soundName=UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
when trying to delete it do this:
NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;
for (UILocalNotification *localNotification in arrayOfLocalNotifications) {
if ([localNotification.alertBody isEqualToString:savedTitle]) {
NSLog(#"the notification this is canceld is %#", localNotification.alertBody);
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
This solution should work for multiple notifications, and your not managing any arrays or dictionaries or user defaults. Your simply using the data you've already saved to the systems notification database.
Hope this helps future designers and developers.
Happy coding guys! :D
Scheduling and removeNotification in swift:
static func scheduleNotification(notificationTitle:String, objectId:String) {
var localNotification = UILocalNotification()
localNotification.fireDate = NSDate(timeIntervalSinceNow: 24*60*60)
localNotification.alertBody = notificationTitle
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.applicationIconBadgeNumber = 1
//play a sound
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertAction = "View"
var infoDict : Dictionary<String,String!> = ["objectId" : objectId]
localNotification.userInfo = infoDict;
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
static func removeNotification(objectId:String) {
var app:UIApplication = UIApplication.sharedApplication()
for event in app.scheduledLocalNotifications {
var notification = event as! UILocalNotification
var userInfo:Dictionary<String,String!> = notification.userInfo as! Dictionary<String,String!>
var infoDict : Dictionary = notification.userInfo as! Dictionary<String,String!>
var notifcationObjectId : String = infoDict["objectId"]!
if notifcationObjectId == objectId {
app.cancelLocalNotification(notification)
}
}
}
Swift 4 solution:
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
for request in requests {
if request.identifier == "identifier" {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["identifier"])
}
}
}
iMOBDEV's solution works perfectly to remove a specific notification (e.g. after deleting the alarm) but it's specially useful when you need to selectively remove any notification that has already fired and is still on the notification center.
A possible scenario would be: the notification for an alarm fires, but the user opens the app without tapping on that notification and schedules that alarm again.
If you want to make sure only one notification can be on the notification center for a given item/alarm, it's a good approach. It also allows you not having to clear all notifications every time the app is opened, shall that fit the app better.
Upon creating a local notification, use NSKeyedArchiver to store it as Data in UserDefaults. You can create a key equal to what you're saving in the notification's userInfo dictionary. If it's associated with a Core Data object, you could use its unique objectID property.
Retrieve it with NSKeyedUnarchiver. Now you're able to delete it using the cancelLocalNotification method.
Update the key on UserDefaults accordingly.
Here's a Swift 3.1 version of that solution (for targets below iOS 10):
Store
// localNotification is the UILocalNotification you've just set up
UIApplication.shared.scheduleLocalNotification(localNotification)
let notificationData = NSKeyedArchiver.archivedData(withRootObject: localNotification)
UserDefaults.standard.set(notificationData, forKey: "someKeyChosenByYou")
Retrieve and delete
let userDefaults = UserDefaults.standard
if let existingNotificationData = userDefaults.object(forKey: "someKeyChosenByYou") as? Data,
let existingNotification = NSKeyedUnarchiver.unarchiveObject(with: existingNotificationData) as? UILocalNotification {
// Cancel notification if scheduled, delete it from notification center if already delivered
UIApplication.shared.cancelLocalNotification(existingNotification)
// Clean up
userDefaults.removeObject(forKey: "someKeyChosenByYou")
}
Swift Version, if need:
func cancelLocalNotification(UNIQUE_ID: String){
var notifyCancel = UILocalNotification()
var notifyArray = UIApplication.sharedApplication().scheduledLocalNotifications
for notifyCancel in notifyArray as! [UILocalNotification]{
let info: [String: String] = notifyCancel.userInfo as! [String: String]
if info[uniqueId] == uniqueId{
UIApplication.sharedApplication().cancelLocalNotification(notifyCancel)
}else{
println("No Local Notification Found!")
}
}
}
You can keep a string with the category identifier when scheduling the notification like so
localNotification.category = NotificationHelper.categoryIdentifier
and search for it and cancel when needed like so
let app = UIApplication.sharedApplication()
for notification in app.scheduledLocalNotifications! {
if let cat = notification.category{
if cat==NotificationHelper.categoryIdentifier {
app.cancelLocalNotification(notification)
break
}
}
}
swift 3-style:
final private func cancelLocalNotificationsIfIOS9(){
//UIApplication.shared.cancelAllLocalNotifications()
let app = UIApplication.shared
guard let notifs = app.scheduledLocalNotifications else{
return
}
for oneEvent in notifs {
let notification = oneEvent as UILocalNotification
if let userInfoCurrent = notification.userInfo as? [String:AnyObject], let uid = userInfoCurrent["uid"] as? String{
if uid == uidtodelete {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
}
}
for iOS 10 use:
let center = UNUserNotificationCenter.current()
center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])
The UILocalNotification object you pass to cancelLocalNotification: will match any existing UILocalNotification object with matching properties.
So:
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"foo";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
will present a local notification that can later be cancelled with:
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
I use this function in Swift 2.0:
static func DeleteNotificationByUUID(uidToDelete: String) -> Bool {
let app:UIApplication = UIApplication.sharedApplication()
// loop on all the current schedualed notifications
for schedualedNotif in app.scheduledLocalNotifications! {
let notification = schedualedNotif as UILocalNotification
let urrentUi = notification.userInfo! as! [String:AnyObject]
let currentUid = urrentUi["uid"]! as! String
if currentUid == uidToDelete {
app.cancelLocalNotification(notification)
return true
}
}
return false
}
Inspired from #KingofBliss's Answer
For Repeated Reminders ( For example you want your alarm to fire on Sun, Sat and Wed at 4 PM , Then you have to make 3 alarms and set repeatInterval to NSWeekCalendarUnit ).
For making Once Only Reminder :
UILocalNotification *aNotification = [[UILocalNotification alloc] init];
aNotification.timeZone = [NSTimeZone defaultTimeZone];
aNotification.alertBody = _reminderTitle.text;
aNotification.alertAction = #"Show me!";
aNotification.soundName = UILocalNotificationDefaultSoundName;
aNotification.applicationIconBadgeNumber += 1;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit| NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
[componentsForFireDate setHour: [componentsForFireDate hour]] ; //for fixing 8PM hour
[componentsForFireDate setMinute:[componentsForFireDate minute]];
[componentsForFireDate setSecond:0] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
aNotification.fireDate = fireDateOfNotification;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
aNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
For Making Repeated Reminder :
for (int i = 0 ; i <reminderDaysArr.count; i++)
{
UILocalNotification *aNotification = [[UILocalNotification alloc] init];
aNotification.timeZone = [NSTimeZone defaultTimeZone];
aNotification.alertBody = _reminderTitle.text;
aNotification.alertAction = #"Show me!";
aNotification.soundName = UILocalNotificationDefaultSoundName;
aNotification.applicationIconBadgeNumber += 1;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit| NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
[componentsForFireDate setWeekday: [[reminderDaysArr objectAtIndex:i]integerValue]];
[componentsForFireDate setHour: [componentsForFireDate hour]] ; // Setup Your Own Time.
[componentsForFireDate setMinute:[componentsForFireDate minute]];
[componentsForFireDate setSecond:0] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
aNotification.fireDate = fireDateOfNotification;
aNotification.repeatInterval = NSWeekCalendarUnit;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
aNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
}
}
For Filtering you array to display it.
-(void)filterNotficationsArray:(NSMutableArray*) notificationArray{
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication] scheduledLocalNotifications]];
NSMutableArray *uniqueArray = [NSMutableArray array];
NSMutableSet *names = [NSMutableSet set];
for (int i = 0 ; i<_dataArray.count; i++) {
UILocalNotification *localNotification = [_dataArray objectAtIndex:i];
NSString * infoDict = [localNotification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
if (![names containsObject:infoDict]) {
[uniqueArray addObject:localNotification];
[names addObject:infoDict];
}
}
_dataArray = uniqueArray;
}
To remove Reminder even it was Once Only or Repeated :
- (void) removereminder:(UILocalNotification*)notification
{
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
NSString * idToDelete = [notification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
for (int i = 0 ; i<_dataArray.count; i++)
{
UILocalNotification *currentLocalNotification = [_dataArray objectAtIndex:i];
NSString * notificationId = [currentLocalNotification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
if ([notificationId isEqualToString:idToDelete])
[[UIApplication sharedApplication]cancelLocalNotification:currentLocalNotification];
}
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
[self filterNotficationsArray:_dataArray];
[_remindersTV reloadData];
}
I expanded on KingofBliss's answer a little, written this a little more Swift2-like, removed some unnecessary code, and added in some crash guards.
To start, when creating the notification, you need to make sure you set the uid (or any custom property really) of the notification's userInfo:
notification.userInfo = ["uid": uniqueid]
Then, when deleting it, you can do:
guard
let app: UIApplication = UIApplication.sharedApplication(),
let notifications = app.scheduledLocalNotifications else { return }
for notification in notifications {
if
let userInfo = notification.userInfo,
let uid: String = userInfo["uid"] as? String where uid == uidtodelete {
app.cancelLocalNotification(notification)
print("Deleted local notification for '\(uidtodelete)'")
}
}
Delete already delivered notification Swift5
UNUserNotificationCenter.current().getDeliveredNotifications{ (requests) in
for request in requests {
if request.request.identifier == "identifier"{
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["identifier"])
}
}
}