I need to have my app fetch data and show an alert to user depending on the response, I'm trying to create a function and then call it on appDelegate class...
the function:
func triggerPushMessages(){
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { (time) in
// I want to perform a request here to show the alert to user
let content = UNMutableNotificationContent()
content.title = "testNotifications on background state"
content.body = "date of notification: \(Date().timeIntervalSinceNow)"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(notificationRequest, withCompletionHandler: { (err) in
if let error = err {print(error);return}
})
}
}
I created this function to test if notifications would show up after I set the timer but what happens is that when I set timer.schedule function pushNotification doesn't work if I remove timer pushNotification works...
the thing is, I need to request data from an Api first wait for the response and then show the push notification to alert the user...
how can I get on with this?
I call this method on:
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.
self.triggerPushMessages()
}
Is it even possible? how apps like whatsapp, telegram, tinder, can handle/ fetch data on background state and then show notifications to user?
thank you in advance for the answer.
I'd like to add that my 60 seconds request are just for test purposes I'll perform the request once an hour...
You cannot add 60 seconds timer in the app background state. its not allowed in iOS. If you want to show notification to the user even if the app is in the background/not, you can send push notifications from your backend server by integrating the APNS(Apple push notifications). because you are saying that you want to show notification to user, once the api response comes. In this case server will have data and It can decide and send notification to the User.
Related
I tried to show up some notification banners on Mac OS with Swift. But i get them only in the notification center, not as banner.
Do you have an idea? Here my simple code:
func showNotification() -> Void {
let notification = NSUserNotification()
notification.title = "Title of notification"
notification.subtitle = "Subtitle of notification"
notification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(notification)
}
#IBAction func btnPressed(_ sender: NSButton) {
showNotification()
testLbl.stringValue = "Button was pressed"
}
You won't get a banner if your app is in the foreground.
Try using…
notification.deliveryDate = Date(timeIntervalSinceNow: 5)
NSUserNotificationCenter.default.scheduleNotification(notification)
and then switch to another app
If, at the time of sending the notification, the app sending the notification is focused, then the notification won't show as a banner. An app can only deliver a banner notification if it is not active in the foreground.
Your code works well when your app is not the main focus, I've just tested it.
So, because you send the notification on a button click, the app is focused when the notification is sent: the notification only goes to the Notification Center, it is not shown as a banner.
This is a rule made on purpose by Apple.
I am trying to call my menu view inside my view controller when the home button is pressed, or for that matter when the user gets a phone call, etc...
My goal is to call the function: toggleMenu() that is inside the QuestionViewController. Here's the code:
class QuestionViewController: UIViewController, MFMailComposeViewControllerDelegate {
///////////
func toggleMenu() {
// Show or hide menu
if menuStackView.isHidden == true {
// Show the menu
print("Showing Menu")
// Update labels
questionNumberMenuLabel.text = questionNumberLabel.text
endTimer()
menuStackView.isHidden = false
animateInMenu()
} else {
// Hide the menu
animateOutMenu()
}
}
I do believe I should utilize the following method found in the AppDelegate.swift file:
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.
}
If I'm on the right track I need help calling the toggleMenu() function of the QuestionViewController class in this method. How do I do that?
Thanks so much!
Use the NotificationCenter and listen for UIApplicationWillResignActiveNotification. The system broadcasts that notification as well as calling your app delegate's applicationWillResignActive method (assuming you have one.)
Listen for notifications (using the method addObserver(forName:object:queue:using:) in your viewDidLoad. If you don't need to support iOS versions < 9.0, you don't need to worry about calling removeObserver - the system takes care of it for you.
I just did change for my notification for iOs 10 and others:
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
let content = UNMutableNotificationContent()
content.body = notifMessage!
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "Upload", content: content, trigger: trigger)
// Schedule the notification.
let center = UNUserNotificationCenter.current()
center.add(request)
}
} else {
let notification = UILocalNotification()
notification.alertBody = notifMessage
notification.fireDate = NSDate() as Date
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(notification)
}
When I run my apps on my device by connect it with the USB it works, but only when the app is in background, it doesn't work when:
i kill the app
when the app is displayed
If you kill the app (by double tapping on home button and then swiping up), that not only terminates the app, but prohibits further background operation of the app (until the user fires it up again). You have to just press the home button and let the app be jettisoned via the normal memory recovery processes. Or you can, for testing purposes, programmatically crash app. But you cannot use springboard (the double tap of home button trick), because affects the permissible background modes of an app.
Regarding the notification when the app is displayed vs if the user taps on the notification vs user manually starts app having disregarding a notification, those are all conveyed to the app in different ways. See the Responding to Notifications and Events section of the UIApplicationDelegate documentation. Or see the App Programming Guide for iOS: Background Execution for general information about background operation.
There are a couple of errors in your code :
1. Title for the notification is missing. You have added the body and sound to the content but the title is missing. Title is a must and if you don't add the title the notification won't show.
content.title = "Some Title"
Do not use init to initialise. These functions can be re-written as :
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "Upload", content: content, trigger: trigger)
The identifier value is same. The identifier value needs to be different for every notification that you schedule. Notifications with same identifier do not appear.
let request = UNNotificationRequest(identifier: some_value, content: content, trigger: trigger)
Trigger time. The time that you specifying in the trigger is for 5 seconds. Which may be less for you to close the app and test for the notification. Just to be on the safe side, make sure this value is at least 1 minute so that you can properly test out if it is working or not.
Hope this helps.
I'm trying to disable a button for certain amount of time, but have an issue. My procedure is below:
I have 3 buttons and all buttons are enabled
After one button is clicked, disable all buttons. In the meantime, sending data via Bluetooth...
Enable all buttons after finishing sending data.
My goal is to prevent button click when sending data via Bluetooth. I tried to use Button.userInteractionEnabled = false and Button.enabled = false, but it will go to button action handler(The one that I press during data sending period) again whenever I enable button after finishing sending data. Does any one know how to disable buttons permanently for a certain amount of time?
What you have to do is disable the button upon clicked and then somehow enable it when the data transfer it's done.
If this data transfer is called asynchronously, it will probably have a parameter where you can send in a completion block:
button.isUserInteractionEnabled = false
sendData(data) {
success in
button.isUserInteractionEnabled = true
}
If it doesn't accept a completion block as a parameter, it might work in a different way, such as using notifications (firing a notification with a specific name):
button.isUserInteractionEnabled = false
sendData(data)
// adding the observer that will watch for the fired notification
NotificationCenter.default.addObserver(self, selector: #selector(self.didFinishSendingData(_:)), name: Notification.Name(rawValue: "NOTIFICATION NAME GOES HERE"), object: nil)
func didFinishSendingData(_ notification: Notification?) {
button.isUserInteractionEnabled = true
}
We could definitely help more if you post a sample of your code.
Why can you achieve this on the main thread with an activityIndicator like below:
let activityIndicator = UIActivityIndicatorView()
activityIndicator.frame = view.frame
activityIndicator.center = view.center
activityIndicator.activityIndicatorViewStyle = .gray
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)
//start activity indicator
activityIndicator.startAnimating()
//send your data via bluetooth on main thread
DispatchQueue.main.async {
//put your sending via bluetooth code here with a completion handler when completes
//then in the completion handler, put below line
activityIndicator.stopAnimating()
}
I'm having a problem with my badge incrementation. I'm using the CloudKit push notifications, and when my app receives a push notification, it increments up from the last notification number.
So even when I reset it to zero using:
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
...in the AppDelegate.swift method, it will start from a higher number like 15 - not 1.
I should mention that my app can receive push notifications. When the above code is triggered, the badges go away (as if the badge counter were reset to 0), but this is temporary.
This has been driving me nuts. Can someone out there help me?
Your badge count is sent inside the payload of the push notification.
[aps: {
alert = {
body = "some body text for notification banner";
title = "title of the banner";
};
badge = 1; // the count that will be set to the badge
sound = default;
}, userInfo: {
// some key/value pairs for further processing. // e.g. deep linking.
}]
You should set a breakpoint on public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) and print the contents of the userInfo dictionary. Check the badge count.