I want to send a notification, on every 60 seconds interval, after application entered to the background. But when you enter the background, notification is sending immediately, after that every 60 seconds is sending notification. I don't want to send notification immediately, how can i do that?
Here is my code,
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]) { (granted, error) in
// Enable or disable features based on authorization.
}
return true
}
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.
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "Hello,", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "Some", arguments: nil)
content.sound = UNNotificationSound.default()
content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1)
content.categoryIdentifier = "com.mahmut.localNotification"
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 60.0, repeats: true)
let request = UNNotificationRequest.init(identifier: "60Sec", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request)
}
try using it this way... instead of 4 you could use your own time... and later in your function you can use the timer concept to send a notification every 60 seconds.
let triggerTime = (Int64(NSEC_PER_SEC) * 4)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, triggerTime), dispatch_get_main_queue(), { () -> Void in
self.callYourFunction()
})
Related
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
I am currently trying to create notifications when a user has new messages. I'm trying to do this with local notifications because I'm very much a beginner and it seems(?) easier than push notifications. My question is, can I check my Firebase database during my background fetch?
What I've experienced is that the background fetch function works- but only before my app memory has been suspended, thus negating the point of the background fetch. I run it, I simulate a background fetch, but unless the app was just open, it does nothing and tells me "Warning: Application delegate received call to -application:performFetchWithCompletionHandler: but the completion handler was never called."
Here's my code if it's useful. I know it probably seems like a funky way to go about this.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//Firebase
FirebaseApp.configure()
//there was other firebase stuff here that I don't think is relevant to this question
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (didAllow, error) in
}
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
myDatabase.child("users").child(userID!).child("hasNewMessages").observeSingleEvent(of: .value) { (snapshot) in
if snapshot.value as! Bool == true {
let content = UNMutableNotificationContent()
content.title = "You have unread messages"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "testing", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
}
It is probably better to look at using push notifications as then your user's don't have to wait until iOS decides to invoke your background fetch; they can be notified of new messages immediately.
However, your problem is as described by the message you see in the console; you need to invoke the completionHandler that was passed to the background fetch method when you have finished your background operation to let iOS know what happened. It uses this information to tune how often and when your background fetch method is called.
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
myDatabase.child("users").child(userID!).child("hasNewMessages").observeSingleEvent(of: .value) { (snapshot) in
if snapshot.value as! Bool == true {
let content = UNMutableNotificationContent()
content.title = "You have unread messages"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "testing", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
completionHandler(.newData)
}
}
I am struggling to get a local notification to run using background fetch.
Ideally what I need is to update my JSON data and if it contains a value then send a local notification to the user.
as yet I am unable to even send a local notification using background fetch.
I have checked out the following: Send Local Notifications while App is running in the background Swift 2.0
ios call function in background mode
and a tutorial https://www.raywenderlich.com/143128/background-modes-tutorial-getting-started
I am still unable to send even a notification let alone do my json query in the background to check for a value.
here is my code for appdelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if let vc = window?.rootViewController as? FirstViewController {
vc.mynotifications()
}
}
and my notification code from the view controller:
func mynotifications() {
let content = UNMutableNotificationContent()
content.title = "title"
content.subtitle = "subtitle"
content.body = "test"
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.5, repeats: false)
let request = UNNotificationRequest(identifier: "timerdone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
I have background fetch enabled in my settings.
Any assistance in getting this to work would be appreciated. If you could also point me in the right direction to tie in the json request in the background that would also be a bonus.
Thanks
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!
I have a public function for local notification and i want to call that function in applicationWillTerminate. When i try this, nothing happens. I'm sure local notification function is ok because when i call that in viewDidLoad, it works properly.
This is the function for local notification;
func scheduleLocalNotification(second: Double) {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.badge = 1
content.title = "Title!"
content.body = "Message!"
content.categoryIdentifier = "id"
content.userInfo = ["key": "value"]
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: second, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
} else {
// Fallback on earlier versions
}
}
AppDelegate;
func applicationWillTerminate(_ application: UIApplication) {
scheduleLocalNotification(second: 30.0)
print("Terminating!")
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
I searched SO for similar problems and found 2 questions, but none of them solve my issue.
Send local notification after termination app swift 2
Local notification on application termination
Edit: Request Authorization;
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if (!launchedBefore) {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Authorization granted!")
} else {
print("Authorization not granted!")
}
}
} else {
let settings = UIUserNotificationSettings(types: [.alert, .badge , .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
}
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
// Override point for customization after application launch.
return true
}
An answer to the second question you linked to seems relevant - applicationWillTerminate is not guaranteed to get called if the system decides to terminate your app while it's in the background.
just a note about applicationWillTerminate: as Apple states, and "Uncommon" says, there is no guarantee that is called.
But I think is a design problem:
a) if You want to add a local notification, do it as soon as user have set it.
b) if You are passing via "applicationWillTerminate" to save cpu time calling "add notification" only when exiting, be sure there is no big penalty saving notifications every time. As a std behaviour, in iOS we should save everything as soon as user are set it.
in my apps I simply add notification on "back" or "close".
c) Be sure to control/reset notifications already set.
If you are only testing iOS behaviour, you are in corner edge, see "eskimo" answer here:
https://forums.developer.apple.com/thread/13557