iOS Local Notification Trigger Handling - ios

I am currently making an app which counts the steps walked and check with goal and release local notification if met.
I have set up the local notification but I want that to trigger just once at that moment. I got this working through dispatch_once_t:
if stepsData >= stepsGoalData {
let localNotification = UILocalNotification()
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
localNotification.fireDate = NSDate()
localNotification.alertBody = "Acheived"
localNotification.soundName = UILocalNotificationDefaultSoundName
}
But in case if the user increases the stepsGoalData, currently the code doesn't trigger the notification. Can someone please provide me with an idea to handle this case. Thank you!

So, you should really just change the check for wether to notify or not so that it considers not just the count but also a flag to indicate if the notification has been made. This can be a var defined beside your stepsGoalData as a simple Bool.
Now, your check would be:
if stepsData >= stepsGoalData && !hasNotified {
hasNotified = true
...
And when you set the stepsGoalData to a new target value you also set hasNotified = false.

Related

Local banner notification for terminating App

I want to show banner notification when user quits the Application. And on tapping that banner I want my Application to open.
func showBanner() {
UIApplication.shared.cancelAllLocalNotifications()
let notif = UILocalNotification.init()
notif.alertBody = "Your Message Here..."
localNotif.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.presentLocalNotificationNow(notif)
}
If I put this code in applicationDidEnterBackground it works fine; But, when I put it in applicationWillTerminate, it doesn't.
Any workaround?
EDIT:
Added fireDate like following:
var dc = DateComponents()
dc.second = 2 // 2 seconds from current date time
notif.fireDate = Calendar.current.date(byAdding: dc, to: Date())
Still not working. Any idea?
The same code works when I set in App communicates using CoreBluetooth in info.plist for Requires Background Modes.
Got the hint from This Answer
Let's hope, Apple does not reject my App.
no guarantee that applicationWillTerminate will ever get called may that is the reasone your code not working . so if your need to do anything before app exist then call applicationDidEnterBackground
more check this iOS - How to guarantee that applicationWillTerminate will be executed

How to Run a Task in swift on a particular date-time in background either application is on or off

I am working on alarm application, i need to schedule alarm on specific time, I use scheduleLocalNotification for scheduling alarms and it's working fine as i want. BUT I need to run to a request to my API server before triggering alarm. In that request I want to check some parameters returning from API server, If that satisfies some condition.
If any one have a method that run on a particular date - time in swift
Please help me for that
func addAlarm (newAlarm: Alarm) {
// Create persistent dictionary of data
var alarmDictionary = NSUserDefaults.standardUserDefaults().dictionaryForKey(ALARMS_KEY) ?? Dictionary()
// Copy alarm object into persistent data
alarmDictionary[newAlarm.UUID] = newAlarm.toDictionary()
// Save or overwrite data
NSUserDefaults.standardUserDefaults().setObject(alarmDictionary, forKey: ALARMS_KEY)
scheduleNotification(newAlarm, category: "ALARM_CATEGORY")
scheduleNotification(newAlarm, category: "FOLLOWUP_CATEGORY")
}
/* NOTIFICATION FUNCTIONS */
func scheduleNotification (alarm: Alarm, category: String) {
let notification = UILocalNotification()
notification.category = category
notification.repeatInterval = NSCalendarUnit.Day
switch category {
case "ALARM_CATEGORY":
notification.userInfo = ["UUID": alarm.UUID]
notification.alertBody = "Time to wake up!"
notification.fireDate = alarm.wakeup
notification.timeZone = NSTimeZone.localTimeZone()
notification.soundName = "loud_alarm.caf"
break
case "FOLLOWUP_CATEGORY":
notification.userInfo = ["UUID": alarm.followupID]
notification.alertBody = "Did you arrive yet?"
notification.fireDate = alarm.arrival
notification.timeZone = NSTimeZone.localTimeZone()
notification.soundName = UILocalNotificationDefaultSoundName
break
default:
print("ERROR SCHEDULING NOTIFICATION")
return
}
print("Notification=\(notification)")
// For debugging purposes
if alarm.isActive {
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
}
Waking up an app through a local notification is not possible, this is available only for remote notifications. According to the Notification Programming Guide:
When a remote notification arrives, the system handles user
interactions normally when the app is in the background. It also
delivers the notification payload to the
application:didReceiveRemoteNotification:fetchCompletionHandler:
method of the app delegate in iOS and tvOS
But there is still a catch; even then it is not guaranteed that the app will be launched since, according to didReceiveRemoteNotification:fetchCompletionHandler: documentation:
However, the system does not automatically launch your app if the user
has force-quit it. In that situation, the user must relaunch your app
or restart the device before the system attempts to launch your app
automatically again.
I don't think there is a guaranteed way to schedule a block for execution in some later moment, independently from the state of the app at that time. Depending on your specific requirements and frequency, you could perhaps register for the fetch background mode and implement application:performFetchWithCompletionHandler: to opportunistically fetch and validate server data. Last note: make sure that you are a responsible background app (from my experience Apple takes this requirement seriously)

ANCS : what is the concept of PositiveAction?

I'm trying to work with the Apple Notification Center Service to make interactions between a Bluetooth peripheral and an iOS device.
In the documentation Apple mention the 2 notification actions: EventFlagPositiveAction and EventFlagNegativeAction…
So far, the Negative part works: once the notification is transmitted to the peripheral, this latter one can trigger the negative action, resulting dismissal of the notification.
But I cannot trigger the Positive side of the force... My Notification has a single action button and I want this button to be considered as the positive action... But I don't know how it works: is it implicit ? do all actions have the positive flag ? or should I do something to make it recognized as the positive one ?
This is more a conceptual question about ACNS, but for information, below is the code I'm using:
1st to register for the local notification in the AppDelegate:
let notificationTypes = UIUserNotificationType.Alert.union(UIUserNotificationType.Sound).union(UIUserNotificationType.Badge)
let launchAction = UIMutableUserNotificationAction()
launchAction.identifier = "LAUNCH_ACTION"
launchAction.title = "OK"
launchAction.activationMode = UIUserNotificationActivationMode.Foreground
launchAction.destructive = false
/* this is this UIMutableUserNotificationAction that I want to trigger from my external device, and should be considered as the famous positive action I am looking for */
let notificationCategory = UIMutableUserNotificationCategory()
notificationCategory.identifier = "LAUNCH_NOTIFICATION"
notificationCategory.setActions([launchAction], forContext: .Minimal)
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: notificationTypes, categories: NSSet(array:[notificationCategory]) as? Set<UIUserNotificationCategory>))
And 2nd, later to create a notification
let localNotification:UILocalNotification = UILocalNotification()
localNotification.alertAction = "Hello"
localNotification.alertBody = "World"
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.hasAction = true
localNotification.category = "LAUNCH_NOTIFICATION"
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
Ok, so then I have had the answer for my question from Apple developer technical Support.
Posting this here, hopefully this will help someone else:
the first thing to understand is that “Positive actions are only wired up for telephony related notifications (incoming call, missed call, and voicemail). There is currently no way to pass through the positive action for an app alert.
Things are easier to understand now…

Repeat Interval is not working correctly for local notifications (Swift) [duplicate]

This question already has answers here:
How to show Notification in Swift more than once?
(2 answers)
Closed 7 years ago.
My repeat interval is going off about every 60 seconds no matter what I have it set to. Here is my code. Also whenever it repeats every 60 seconds, two notifications go off at once. To clarify what I am trying to do, I want my notification to go off once a week to remind the players of my sprite kit game to come back and play.
let localNotification = UILocalNotification() // Creating an instance of the notification.
localNotification.alertTitle = "Title"
localNotification.alertBody = "Body"
localNotification.alertAction = "Launch"
localNotification.repeatInterval = .Hour
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.soundName = UILocalNotificationDefaultSoundName // Use the default notification tone/ specify a file in the application bundle
localNotification.applicationIconBadgeNumber = 1 // Badge number to set on the application Icon.
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
UIApplication.sharedApplication().scheduleLocalNotification(localNotification) // Scheduling the notification.
What happened was that you tried to schedule a invalid repeatInterval unit. The minimum repeat interval unit it is .Minute. So What happened when you tried a valid unit it worked but you were still receiving the first schedule notification that was set by default to repeat every minute.
Just cancel all previous schedule notifications and schedule a new one.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instm/UIApplication/cancelAllLocalNotifications

How do I properly use cancelLocalNotification?

I believe I am using cancelLocalNotification improperly.
I have a recurring notification that runs conditionally, which was created using the following code:
let localNotification: UILocalNotification = UILocalNotification()
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive..."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.repeatInterval = .Minute
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
This notification successfully runs every single minute (for testing purposes). Obviously, I'd like a way to conditionally remove these notifications, so I've tried to use cancelLocalNotification to do so.
How I think cancelLocalNotification works
My intuition is that cancelLocalNotification will remove all the notifications for that specific notification object. Here's how I'm using it.
UIApplication.sharedApplication().cancelLocalNotification(localNotification)
What actually happens
I've stepped through my function and verified that the cancelLocalNotification code does get called. However, I keep getting my notification every minute.
My Question
How do I properly cancel a UILocalNotification that has been scheduled?
Full code:
static func evaluateMemberStatusNotifications() {
let userDefaults = Global.app.userDefaults
let localNotification: UILocalNotification = UILocalNotification()
print("evaluating profile notifications")
// is the user active? if so no notification
let isActive : Bool = userDefaults.valueForKey("ActiveMember") as! Bool // false == inactive
print("is the user active?")
if !isActive {
print("user is not active, checking if notification code has run")
// if userDefaults is nil for this value, we'll set it to false
if (userDefaults.valueForKey("ProfileNotificationHasRun") == nil) {
print("nil! setting ProfileNotificationHasRun to 'false'")
userDefaults.setValue(false, forKey: "ProfileNotificationHasRun")
}
let statusNotification = userDefaults.valueForKey("ProfileNotificationHasRun") as! Bool
// has this code been run? If not run it
if !statusNotification {
print("running notification code")
// we schedule a notification
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.category = "status"
localNotification.repeatInterval = .Day
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
userDefaults.setValue(true, forKey: "ProfileNotificationHasRun")
} else {
print("notification code has already run, time interval has been set")
}
} else {
print("member is active, remove Inactive notification")
// if the member is active, we remove the notification so the user doesn't
// keep getting notified
UIApplication.sharedApplication().cancelLocalNotification(localNotification)
userDefaults.setValue(false, forKey: "ProfileNotificationHasRun")
}
}
You're creating a new UILocalNotification (line 3 of your gist) and then cancelling it. That new notification was never scheduled. You need to get the existing, scheduled notification object and cancel that.
You can access your existing, scheduled notifications through the UIApplication.sharedApplication().scheduledLocalNotifications array.
Or you could just cancel all scheduled local notifications by calling UIApplication.sharedApplication().cancelAllLocalNotifications().
UPDATE
Each call to evaluateMemberStatusNotifications creates a new instance of UILocalNotification, then (depending on the ActiveMember value) either configures and schedules that new notification, or tries to delete the new (unscheduled) notification.
Instead, you should just create a new notification in the !isActive branch where you want to schedule it.
In the other branch, you need to find the existing notification in the scheduledLocalNotifications array and (if you find it) cancel that existing notification.
Since you say you have other notifications that you don't want to mess with, you should use the userInfo property of the notification to identify it. For example, when configuring the notification before scheduling it:
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive. You may continue using this application though some features may not be available to you until your membership is reinstated."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.category = "status"
localNotification.repeatInterval = .Day
// *** NEW
localNotification.userInfo = [ "cause": "inactiveMembership"]
And when you want to cancel the existing notification:
let maybeNotification = UIApplication.sharedApplication().scheduledLocalNotifications?.filter({ (notification: UILocalNotification) -> Bool in
notification.userInfo?["cause"] as? String == "inactiveMembership"
}).first
if let notification = maybeNotification {
UIApplication.sharedApplication().cancelLocalNotification(notification)
}

Resources