How to get notification to repeat daily - swift

When I call my notification function, it will trigger at the original time. However, I never get another notification after that. I noticed this post was dealing with a similar issue. I changed my code to mimic the solution. I still didn't receive another notification.
Here is the code:
static func scheduleNotification(hour:Int, minutes:Int, completion: #escaping (Bool) -> ()) {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Hello "
notificationContent.subtitle = "Now might be a good time for a check in"
var dateInfo = DateComponents()
dateInfo.hour = hour
dateInfo.minute = minutes
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
print(trigger.nextTriggerDate()!)
let request = UNNotificationRequest(identifier: Notifications.notificationIdentifier, content: notificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil {
print("\(error)")
completion(false)
} else {
completion(true)
}
})
}
The intention is to have it trigger daily at 4:00pm.
scheduleNotification(hour: 16, minutes:00, completion: {success in
if success {
print("Successfully scheduled notification")
} else {
print("Could not schedule notification")
}
})
I printed the result of the nextTriggerDate function to see if it would return the original trigger date or the date of the following day. In this case, the date is 4-18-2018.
The trigger that gets returned is
2018-04-18 23:00:00 +0000
I'm also not sure why the date returned adds 7 hours to my intended trigger time. The notification still fires at 4:00. Thoughts?

short answer
add
dateInfo.timeZone = TimeZone(abbreviation: "UTC")
and it will work like expected.
explanation
I tried myself with hour 16 and minutes 0.
I got 14:00 as result. The reason is because I'm living in Germany and Germany (GMT+2, summer time) has at the moment +2 hours distance to UTC.
The defaults timezone of my device is GMT+2. I add 16 hours and DateComponent handle this date as GMT+2 but converts that value to UTC.
So 16 (input) - 2 (GMT) = 14 UTC.
I'm always try to work with UTC dates... everything else causes me a headache.

Related

Reoccurring local notification for UTC time

I looked all over stack overflow and was only able to find reoccurring local notifications for a specific time. However, I am trying to find information on how to make a reoccurring local notification based off a UTC time. The reason behind when you set up a reoccurring notification, it will stay to that specific time.
For example, at the moment 00:00:00 UTC is 5pm eastern time but when day light savings hits in a few months, the new time will be 4pm. However, the reoccurring notification is still set to 5pm. So this notification is now one hour off because of day light savings.
I am trying to figure out how to accomplish this, so the local notification will move properly with day light savings. I am not sure if this is possible since the reoccurring is set to a specific time, but I would love to find more information on this.
By default current Time Zone is considered for delivering local notifications. To use UTC time while registering for local notification, you need to set Time Zone to UTC.
import UIKit
import UserNotifications
//get the notification center
let center = UNUserNotificationCenter.current()
//create the content for the notification
let content = UNMutableNotificationContent()
content.title = " Title"
content.subtitle = "SubTitle"
content.body = "jvsvsvasvbasbvfasfv"
content.sound = UNNotificationSound.default
var dateComp = DateComponents()
dateComp.timeZone = TimeZone(identifier: "UTC") // set time zone to UTC
dateComp.day = 1;
dateComp.hour = 08;
dateComp.minute = 00;
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComp, repeats: true)
//create request to display
let request = UNNotificationRequest(identifier: "ContentIdentifier", content: content, trigger: trigger)
//add request to notification center
center.add(request) { (error) in
if error != nil {
print("error \(String(describing: error))")
}
}
Above code sets notification every morning 8 am UTC time.

Repeat Local Notification at a specific time and after same time at intervals

It could be duplicate of Question asked - Repeating local notification daily at a set time with swift
But UILocalNotifications are deprecated iOS 10
I am working on alarm app, I need 2 things
1. local notification on a time
2. Repeat after a time interval
/// Code used to set notification
let content = UNMutableNotificationContent()
content.body = NSString.localizedUserNotificationString(forKey: titleOfNotification, arguments: nil)
content.userInfo=[]
Code That work fine hit notification at exact time
/* ---> Working Fine --> how i can repeat this after 60 second if untouched
let triggerDaily = Calendar.current.dateComponents([.hour,.minute,], from: dates)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: weekdays.isEmpty == true ? false : true)
*/
/// ---> Making it Repeat After Time - How Time is passed here ?
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 60, repeats: true)
/// ---> Adding Request
let request = UNNotificationRequest(identifier:dateOfNotification, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request){(error) in
if (error != nil){
print(error?.localizedDescription ?? "Nahi pta")
} else {
semaphore.signal()
print("Successfully Done")
}
}
How I can achieve both things at same time ?
You can use UNUserNotificationCenter for local notifications, meanwhile, for the repeating notification you can use the performFetchWithCompletionHandler method, for this method you have to set the minimum time interval for the method to be called.
Please follow the link for more details -
https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/updating_your_app_with_background_app_refresh
ALSO Sample code -
func scheduleLocalNotification(subtitle: String, description: String, offerID: String) {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "New lead for " + subtitle
notificationContent.body = description
notificationContent.userInfo = ["aps":
["alert": [
"title": subtitle,
"body": description,
"content-available": "1"
],
"ofrid": offerID,
"type": "BLBGSync",
"landinguri": "abc.com",
]
]
// Create Notification Request
let triggertime = UNTimeIntervalNotificationTrigger(timeInterval: 3600, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: "YOUR_IDENTIFIER", content: notificationContent, trigger: triggertime)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}

In Swift, How Can I Safely Ensure Data is Retrieved (Date & Time) from Google Before Continuing Code?

I found this other question here which has a good write-up, however it describes how to use completion handlers in a urlSession in order to segue... but I was having a hard time applying it to my case scenario.
What I want to do:
Look up the current date and time in "UTC" on google's servers.
Ensure I have retrieved the data before continuing
Hold that retrieved data (date and time) in a string variable.
What I've written so far in code works... sometimes... but it's not robust. I'll often get a crash, and from my limited knowledge, I was able to research the fact that it may have to do with the task continuing on before the data has actually been retrieved (sometimes it says what I was looking up is 'nil').
Here is the part where I call the function to do the fetch:
func handleDateAndTimeFetch (fetch: String, calculate: Bool) {
serverTimeReturn { (getResDate) -> Void in //Handles the value received from Google and formats it
let dFormatter = DateFormatter()
dFormatter.dateStyle = .short
dFormatter.timeStyle = .medium
dFormatter.timeZone = TimeZone(abbreviation: "UTC")
let dateAndTimeNow = dFormatter.string(from: getResDate!)
}
}
...and here is the function:
//Call Google's server for the current date & time in UTC (Coordinated Universal Time)
func serverTimeReturn(completionHandler:#escaping (_ getResDate: Date?) -> Void){
let url = URL(string: "https://www.google.com")
let task = URLSession.shared.dataTask(with: url!) {(data, response, error) in
let httpsResponse = response as? HTTPURLResponse
if let contentType = httpsResponse!.allHeaderFields["Date"] as? String {
let dFormatter = DateFormatter() //A formatter object
dFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z"
let serverTime = dFormatter.date(from: contentType)
completionHandler(serverTime)
}
}
print("Retrieved date value")
task.resume()
}
...And finally, here are the errors I get the odd time. If you're able, can you also help me understand what these errors are saying exactly?:
2018-04-25 21:05:55.071137-0400 JeegO[8768:3548654] TIC TCP Conn Failed [3:0x1c0176200]: 1:50 Err(50)
2018-04-25 21:05:55.071486-0400 JeegO[8768:3548654] Task <5C958839-0A62-4E06-A811-8ED9D8A4709C>.<1> HTTP load failed (error code: -1009 [1:50])
2018-04-25 21:05:55.078817-0400 JeegO[8768:3548645] Task <5C958839-0A62-4E06-A811-8ED9D8A4709C>.<1> finished with error - code: -1009
(lldb)
I want to ensure I can retrieve this simple data (Date & Time) before I continue on with my app, so I REALLY do appreciate your help in solving this little problem so I can move on in confidence :)
Thanks so much!
Nothing is wrong with your code. You are getting error code -1009 which means your internet connection is not established.
NSURLErrorNotConnectedToInternet
Returned when a network resource was requested, but an internet connection is not established and cannot be established automatically, either through a lack of connectivity, or by the user's choice not to make a network connection automatically.

Notification Center and changing timezones

Swift 4 & >iOS 10.0
I want to schedule a local notification at a certain date and at a given time (let's say 3PM). I want the notifications to always be fired at 3PM, whatever the timezone I am in (automatic rescheduling of notifications according to timezones).
Previously, you could tweak UILocalNotifications' time zone to achieve exactly this, like perfectly explained in this SO post. However, in >iOS 10.0, UILocalNotifications is deprecated.
Here is my code:
func scheduleNotification(title: String, message: String, atDate: Date){
let center = UNUserNotificationCenter.current()
// Create content
let content = UNMutableNotificationContent()
content.title = title
content.body = message
content.sound = UNNotificationSound.default()
// Create trigger
let calendar = Calendar(identifier: .gregorian)
let triggerDate = calendar.dateComponents([.year,.month,.day,.hour,.minute,.second,], from: atDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false)
// Create identifier
let identifier = "\(UUID())"
// Create request & add to center
let request = UNNotificationRequest(identifier: identifier,
content: content,
trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
})
}
Question:
How do you make the notification triggers properly with changing timezones ?
So, I managed to make it work. The triggerDate has a timeZone variable which is automatically nil, exactly like UILocalNotification.
triggerDate.timeZone behaves exactly like UILocalNotification.timeZone (behaviour described in this post, the same as mentioned in the question).
One of the reason it did not seem to work on the simulator was because I was not restarting the simulator when changing the timezone. Restarting will make everything work as expected.
Nota bene: Maybe a restart is not mandatory but since it's not obvious how much time a running simulator will take to detect the new timezone, I think restarting it is the most efficient solution.

Expiration date of the auto renewing subscription

Have a question about expiration date of the subscription. I have following code with works without errors where I validate receipt and where I have a little issue. My expiration date doesn't change. So If I buy subscription again and again my expiration date stay the same and I always fall into else clause because expiration date is "older" than "new" one.
What I do wrong with it?
private func complete(transaction: SKPaymentTransaction) {
let receiptValidator = ReceiptValidator()
let result = receiptValidator.validateReceipt()
switch result {
case let .success(receipt):
guard let purchase = receipt.inAppPurchaseReceipts?.filter({ $0.productIdentifier == IAPProducts.autoRenewable.rawValue }).first else {
NotificationCenter.default.post(name: Notification.Name(transaction.payment.productIdentifier), object: nil)
return
}
if purchase.subscriptionExpirationDate?.compare(Date()) == .orderedDescending {
print("expirationDate: \(purchase.subscriptionExpirationDate!)")
print(" now's date: \(Date())")
// true clause stuff
} else {
// false clause stuff
print("Subscription has ended")
}
// other stuff
case let .error(error):
print("receipt is invalid")
print(error.localizedDescription)
}
paymentQueue.finishTransaction(transaction)
}
So the console output like this:
expirationDate: 2017-11-01 09:08:11 +0000
now's date: 2017-11-01
10:35:11 +0000
What do I miss?
Thank you!
Oh I found out that my sandbox user made too many transactions. So I create another one and now code works as expected.