Swift: how to schedule local notifications with dynamic content
Push notification is best option for your if you want to display weather forecast
.
More about this : https://stackoverflow.com/a/41901767/3901620
How do I send local notifications at a specific time in Swift?
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")
}
}
}
}
How to schedule a same local notification in swift
UILocalNotification
has a repeatInterval
property that lets you specify how often the notification should repeat. Note that this is an NSCalendarUnit
, not just an arbitrary number, so you can only make a notification repeat once per calendar unit (second, minute, hour, day, week, month, etc.). See the NSCalendarUnit
documentation for more options.
For example, you can make a notification repeat every month with:
notification.repeatInterval = .CalendarUnitMonth
How to implement scheduled local notification
var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.hour = 1
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
This basically takes todays date and sets the time to 1am. Using: UNCalendarNotificationTrigger(dateMatching:
you are telling the notification to trigger at 1am today and then repeat at the same time each day.
To trigger a notification based on a time interval you should use the UNTimeIntervalNotificationTrigger
.
// Fire in 60 minutes (60 seconds times 60)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: (60*60), repeats: false)
iOS local notification base on day, time frame and number of times?
If you want to schedule multiple notifications, you need to create multiple notification triggers and register them.
something like:
// Simple extension if you have to create multiple of the same object
extension DateComponents {
static func triggerFor(hour: Int, minute: Int) -> DateComponents {
var component = DateComponents()
component.calendar = Calendar.current
component.hour = hour
component.minute = minute
component.weekday = 1
return component
}
}
// Add each trigger into an array with the correct date component
let triggers = [
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 1, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 2, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 3, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 4, minute: 0), repeats: true),
UNCalendarNotificationTrigger(dateMatching: DateComponents.triggerFor(hour: 5, minute: 0), repeats: true)
]
// Iterate through the array and register the notification with the system
for trigger in triggers {
// Create the content of the notification
let content = UNMutableNotificationContent()
content.title = "My Notification Title"
content.body = "Body of Notification"
// Create the request
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString,
content: content, trigger: trigger)
// Schedule the request with the system.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if error != nil {
// Handle any errors.
}
}
}
Schedule local notification every n days (timezone safe)
You can set them up upfront using UNCalendarNotificationTrigger
for an n
number of times and using an adjusted calendar for the current timeZone
import SwiftUI
class NotificationManager: NSObject, UNUserNotificationCenterDelegate{
static let shared: NotificationManager = NotificationManager()
let notificationCenter = UNUserNotificationCenter.current()
private override init(){
super.init()
requestNotification()
notificationCenter.delegate = self
getnotifications()
}
func requestNotification() {
print(#function)
notificationCenter.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if let error = error {
// Handle the error here.
print(error)
}
// Enable or disable features based on the authorization.
}
}
/// Uses [.day, .hour, .minute, .second] in current timeZone
func scheduleCalendarNotification(title: String, body: String, date: Date, repeats: Bool = false, identifier: String) {
print(#function)
let content = UNMutableNotificationContent()
content.title = title
content.body = body
let calendar = NSCalendar.current
let components = calendar.dateComponents([.day, .hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: repeats)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
notificationCenter.add(request) { (error) in
if error != nil {
print(error!)
}
}
}
///Sets up multiple calendar notification based on a date
func recurringNotification(title: String, body: String, date: Date, identifier: String, everyXDays: Int, count: Int){
print(#function)
for n in 0..<count{
print(n)
let newDate = date.addingTimeInterval(TimeInterval(60*60*24*everyXDays*n))
//Idenfier must be unique so I added the n
scheduleCalendarNotification(title: title, body: body, date: newDate, identifier: identifier + n.description)
print(newDate)
}
}
///Prints to console schduled notifications
func getnotifications(){
notificationCenter.getPendingNotificationRequests { request in
for req in request{
if req.trigger is UNCalendarNotificationTrigger{
print((req.trigger as! UNCalendarNotificationTrigger).nextTriggerDate()?.description ?? "invalid next trigger date")
}
}
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.banner)
}
}
class ZuluNotTriggerViewModel:NSObject, ObservableObject, UNUserNotificationCenterDelegate{
@Published var currentTime: Date = Date()
let notificationMgr = NotificationManager.shared
///Sets up multiple calendar notification based on a date
func recurringNotification(title: String, body: String, date: Date, identifier: String, everyXDays: Int, count: Int){
print(#function)
notificationMgr.recurringNotification(title: title, body: body, date: date, identifier: identifier, everyXDays: everyXDays, count: count)
//just for show now so you can see the current date in ui
self.currentTime = Date()
}
///Prints to console schduled notifications
func getnotifications(){
notificationMgr.getnotifications()
}
}
struct ZuluNotTriggerView: View {
@StateObject var vm: ZuluNotTriggerViewModel = ZuluNotTriggerViewModel()
var body: some View {
VStack{
Button(vm.currentTime.description, action: {
vm.currentTime = Date()
})
Button("schedule-notification", action: {
let twoMinOffset = 120
//first one will be in 120 seconds
//gives time to change settings in simulator
//initial day, hour, minute, second
let initialDate = Date().addingTimeInterval(TimeInterval(twoMinOffset))
//relevant components will be day, hour minutes, seconds
vm.recurringNotification(title: "test", body: "repeat body", date: initialDate, identifier: "test", everyXDays: 2, count: 10)
})
Button("see notification", action: {
vm.getnotifications()
})
}
}
}
struct ZuluNotTriggerView_Previews: PreviewProvider {
static var previews: some View {
ZuluNotTriggerView()
}
}
Related Topics
Setting a Stateobject Value from Child View Causes Navigationview to Pop All Views
Recognizing Touch Events Only Inside the Masked View
Dismiss Keyboard with Swipe Gesture
Include Pods in Main Target and Not in Watchkit Extension
How to Determine If a Business Is Open Given the Hours of Operation (Swift-Ios)
Custom Sequence for Swift Dictionary
How to Calculate a Random Cgpoint Which Does Not Touch a Uiview
What Are the First Two Columns in Scnmatrix4
App Groups Forsecurityapplicationgroupidentifier Returns Nil
How to Make a Uiimage Scrollable Inside a Uiscrollview
Swift - Convert Values in Array to Doubles or Floats
Avaudiocompressedbuffer to Uint8 Array and Vice Versa
Saving Already Created Live Photos
How Posting One Signal Notification's Additional Data and Receiving That