Local Notification when date is set on a UIPickerView? - ios

I want to set up a local notification when a user sets a date on a UIPicker.
At the moment I have no code because I am not sure where to start.

I assume that you want the user to choose when to send the notification, so:
First, authorise for notifications in the app delegate, like so:
import UserNotifications
class AppDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
// Enable or disable features based on authorization
}
return true
}
}
Next, assuming you've created a datePicker and connected it to the code:
#IBOutlet var datePicker: UIDatePicker!
Your function for scheduling the notification is:
func scheduleNotification() {
let content = UNMutableNotificationContent() //The notification's content
content.title = "Hi there"
content.sound = UNNotificationSound.default()
let dateComponent = datePicker.calendar.dateComponents([.day, .hour, .minute], from: datePicker.date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false)
let notificationReq = UNNotificationRequest(identifier: "identifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(notificationReq, withCompletionHandler: nil)
}
You can read more about UserNotifications and Notification Triggers here: https://developer.apple.com/documentation/usernotifications

Related

Scheduling local notifications in swift

In my app I applied a code that stops a notification being sent every time user goes to a specific view controller, but now the notification is sent only once at the very beginning after download. How can I change it to show the notification only once each time after the app had been refreshed? Here's the code:
import UIKit
import UserNotifications
class firstViewController: UIViewController, UNUserNotificationCenterDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.badge,.sound,.alert]) { granted, error in
if error == nil {
print("User permission is granted : \(granted)")
}
}
let defaults = UserDefaults.standard
// Check for flag, will be false if it has not been set before
let userHasBeenNotified = defaults.bool(forKey: "userHasBeenNotified")
// Check if the flag is already true, if it's not then proceed
guard userHasBeenNotified == false else {
// Flag was true, return from function
return
}
// Step-2 Create the notification content
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "Welcome"
// Step-3 Create the notification trigger
let date = Date().addingTimeInterval(2)
let dateComponent = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false)
// Step-4 Create a request
let uuid = UUID().uuidString
let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger)
// Step-5 Register with Notification Center
center.add(request) { error in
defaults.setValue(true, forKey: "userHasBeenNotified")
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound,.banner,.badge])
}
}
When you store something to UserDefaults, it stays even after the app closes. That's why the notification doesn't show again.
If you don't want it to be persisted across app launches, you should set it to false at the app launch time (I assume that's what you mean by refreshed):
You can add this to your UIApplicationDelegate (or add the line to existing didFinishLaunchingWithOptions):
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// this clears the flag
UserDefaults.standard.setValue(false, forKey: "userHasBeenNotified")
return true
}
Or, if you have a way of sharing state throughout the app (singleton perhaps), you can avoid UserDefaults and save it as a member of whatever class you use.

How to create reminders that don't have to be shown in the Apple's Reminders app

With the following code I can successfully create a reminder event and add an alarm to it that triggers 10 seconds after the event has been created. What I don't like about the way the reminder is created is that it shows in the Apple's Reminders app and when you get the notification message in your device, it shows the Reminders' app icon.
Is it possible to make the reminder private so it doesn't show in Apple's Reminders app? If not, what are my options to achieve such of task?
Note: I don't mind storing the reminders in the standard reminders local database as long as they don't show in the default Reminders app.
import EventKit
class ViewController: UIViewController{
var eventStore = EKEventStore()
override func viewDidLoad(){
super.viewDidLoad()
// get user permission
eventStore.requestAccess(to: EKEntityType.reminder, completion: {(granted, error) in
if !granted{
print("Access denied!")
}
})
}
#IBAction func createReminder(_ sender: Any) {
let reminder = EKReminder(eventStore: self.eventStore)
reminder.title = "Get Milk from the Store"
reminder.calendar = eventStore.defaultCalendarForNewReminders()
let date = Date()
let alarm = AKAlarm (absoluteDate: date.addingTimeInterval(10) as Date)
reminder.addAlarm(alarm)
do {
try eventStore.save(reminder, commit: true)
} catch let error {
print("Error: \(error.localizedDescription)")
}
}
}
FYI - To make the above code work you would need to add the NSRemindersUsageDescription key in the info.plist file.
Just for the record, what I was looking for was User Notifications.
Here is a complete example.
User Notifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
if granted{
print("User gave permissions for local notifications")
}else{
print("User did NOT give permissions for local notifications")
}
}
return true
}
override func viewDidLoad() {
super.viewDidLoad()
setReminderAtTime()
}
func setReminderAtTime(){
let reminderTime:TimeInterval = 60
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Notification Message!."
content.sound = .default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: reminderTime, repeats: false)
let request = UNNotificationRequest(identifier: "reminderName", content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil{
print("Error = \(error?.localizedDescription ?? "error local notification")")
}
}
}

How do I send local notifications at a specific time in Swift?

I have been looking all over for an answer on how to send notifications at a specific time of day. I need it to display a local notification to the user's device every weekday at 8:00 A.M. I am aware that this question has been answered before. I found a Stack Overflow question: Local Notifications at a specific time
Unfortunately, it was pretty outdated as most of the code was removed from Swift since iOS 11 was released. I needed a more recent answer. I am kind of new to Swift programming. If someone could help me out and give me a more recent answer, that would be amazing!
This is an example of what I have used for scheduling local notifications using Notification Centre.
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "My title"
content.body = "Lots of text"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "yourIdentifier"
content.userInfo = ["example": "information"] // You can retrieve this when displaying notification
// Setup trigger time
var calendar = Calendar.current
calendar.timeZone = TimeZone.current
let testDate = Date() + 5 // Set this to whatever date you need
let trigger = UNCalendarNotificationTrigger(dateMatching: testDate, repeats: false)
// Create request
let uniqueID = UUID().uuidString // Keep a record of this if necessary
let request = UNNotificationRequest(identifier: uniqueID, content: content, trigger: trigger)
center.add(request) // Add the notification request
The Date object (represented by testDate above) can be whatever date you want. It is often convenient to create it from DateComponents.
You will need to ask permission for local notifications in the App Delegate at startup to allow this to work. Here is an example.
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Ask permission for notifications
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Permission granted")
} else {
print("Permission denied\n")
}
}
}
}
Swift 5
This is an example of what I have used for scheduling local notifications using Notification Center.
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//MARK: Authorization
let center = UNUserNotificationCenter.current()
//Delegate for UNUserNotificationCenterDelegate
center.delegate = self
//Permission for request alert, soud and badge
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
// Enable or disable features based on authorization.
if(!granted){
print("not accept authorization")
}else{
print("accept authorization")
center.delegate = self
}
}
return true
}
}
send notification
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "We have a new message for you", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "Open the app for see", arguments: nil)
content.sound = UNNotificationSound.default
content.badge = 1
let identifier = id.uuidString
//Receive notification after 5 sec
//let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
//Receive with date
var dateInfo = DateComponents()
dateInfo.day = day //Put your day
dateInfo.month = month //Put your month
dateInfo.year = year // Put your year
dateInfo.hour = 8 //Put your hour
dateInfo.minute = 0 //Put your minutes
//specify if repeats or no
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
print(identifier)
center.add(request) { (error) in
if let error = error {
print("Error \(error.localizedDescription)")
}else{
print("send!!")
}
}
remembering to read this in the documentation:
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/index.html#//apple_ref/doc/uid/TP40008194-CH3-SW1

Setting local notification for current date and time is not working using Swift 3

I am new in local notification and I have to implement a task. I have a reminder date and text so I want to show local notification according to reminderDate and current date.
If reminder date is 7 days before to current date then I have to show notification
If reminder date is 2 days before to current date then I have to show reminders.
On the same day in evening 5 PM I have to show reminder text.
My sample code is:
import UIKit
import EventKit
import UserNotifications
class ViewController: UIViewController, UNUserNotificationCenterDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//getNotificationSettings()
UNUserNotificationCenter.current().delegate = self
}
//Button Alarm
#IBAction func btnAlarm(_ sender: Any) {
let date = Date()
/*let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
dateFormatter.timeZone = TimeZone.current
let dateString = dateFormatter.string(from: date)
let originalDate = dateFormatter.date(from: dateString)
//let dateInFormat = dateFormatter.stringFromDate(Date())*/
scheduleNotification(at: date!)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == "answer1" {
print("Answer 1")
}
else if response.actionIdentifier == "textNotification" {
print("Answer Text Notification")
}
completionHandler()
}
//Schedule Notification
func scheduleNotification(at date: Date) {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
let content = UNMutableNotificationContent()
content.title = "Tutorial Reminder"
content.body = "Just a reminder to read your tutorial over at appcoda.com!"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "myCategory"
if let path = Bundle.main.path(forResource: "logo", ofType: "png") {
let url = URL(fileURLWithPath: path)
do {
let attachment = try UNNotificationAttachment(identifier: "logo", url: url, options: nil)
content.attachments = [attachment]
} catch {
print("The attachment was not loaded.")
}
}
let request = UNNotificationRequest(identifier: "textNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
}
And I have check the permission in Appdelegate.swift file :-
import UIKit
import CoreData
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//getNotificationSettings()
registerForPushNotifications()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// 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 invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 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.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// 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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
//self.saveContext()
}
/*func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
print("Permission granted: \(granted)")
}
}*/
/*func getNotificationSettings() {
let notificationSettings = UIUserNotificationSettings(types: [.alert, .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(notificationSettings)
}*/
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) {
(granted, error) in
print("Permission granted: \(granted)")
}
}
How can I achieve that above task and why local notification is not showing for current date in my code is local time or anything else?

iOS: How can I notify/alert the user when he/she suspends the app?

I'm tasked to implement a feature that sends qualified users a link to an online survey when they first suspend the app. Ideally I'd do this with a Notification of some type (e.g. local, push). Is there a way to have the app trigger a notification to the user when they suspend such that tapping it would open the survey link (perhaps via relaunching the app first)?
In AppDelegate, you need to save whether or not the user has ever opened the app before.
AppDelegate
//make sure to import the framework
//additionally, if you want to customize the notification's UI,
//import the UserNotificationsUI
import UserNotifications
//default value is true, because it will be set false if this is not the first launch
var firstLaunch: Bool = true
let defaults = UserDefaults.standard
//also make sure to include *UNUserNotificationCenterDelegate*
//in your class declaration of the AppDelegate
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
//get whether this is the very first launch
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let bool = defaults.object(forKey: "firstLaunch") as? Bool {
firstLaunch = bool
}
defaults.set(false, forKey: "firstLaunch")
defaults.synchronize()
//ask the user to allow notifications
//maybe do this some other place, where it is more appropriate
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in}
return true
}
//schedule your notification when exiting the app, if necessary
func applicationDidEnterBackground(_ application: UIApplication) {
//update the variable
if let bool = defaults.object(forKey: "firstLaunch") as? Bool {
firstLaunch = bool
}
if !firstLaunch {
//abort mission if it's not the first launch
return
}
//customize your notification's content
let content = UNMutableNotificationContent()
content.title = "Survey?"
content.body = "Would you like to take a quick survey?"
content.sound = UNNotificationSound.default()
//schedule the notification
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "takeSurvey", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request, withCompletionHandler: nil)
}
At last, handle the response you got and open your link. That's it!

Resources