how to update data when app is terminated - ios

Is there any way to grab the information that comes from the firebase notification when the app is closed in the background?
I managed to capture it and save it in the following function
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
when it is in the background and in execution, but I cannot do it when it is closed
I managed to capture it and save it in the following function

It depends on what you are trying to do.
When the app is sent to the background there are certain life cycle changes that happen and the AppDelegate is notified about this, which gives you a chance to do some small tasks like cleanup, or make a last minute save. But you will only get a limited time to do so (I think its usually around 1 minute, you can ask for more time I believe but that only extends it to about 3 mins).
An example of these life cycle events is applicationWillTerminate, this method is called just before the app terminates and gives you a small window to make a last minute save.
Once your app is suspended you can only do limited things, like background fetch, receive location information, receive push notifications etc.
Background Modes is a good guide on what you can do in the background
When your app is terminated, there is pretty much nothing you can do.

Related

What lifecycle method is called when app is terminated by system in the background?

I have the following function which is activated when a silent push notification arrives in the app:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
var runCount = 0
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
runCount += 1
self.writeStepInDb(function: "Timer-\(runCount)")
}
}
When this function runs we expect that the app is suspended (by user or system doesn't matter).
The line self.writeStepInDb(function: "Timer-\(runCount)") is essentially my way of seeing that the Timer is indeed running in the background, since I have no way of reading logs when app is woken up and run in the background, instead I just have the timer constantly write to a DB and that's how I know it's running.
At the current moment, based on DB entries, I see that it will run for about ~30 seconds and then will get killed.
Does anyone know what lifecycle method is called when the app is killed after such a situation? I want to be able to start up another background task before the app is killed and thus prolong it's life some more, but I need to know right before it is about to be killed.
My main goal is to prolong the app's life in the background state (awakened by silent push notification) for as long as possible.
Once again, what is the lifecycle method called when the timer dies?
Thanks. From what I can tell, it seems that for certain terminations, like mine, there is no lifecycle method called for termination.
This is because background task duration extension is frowned upon by the system and so it seems the system will terminate such apps in a very draconian fashion lol. No lifecycle method to do last minute things, just straight up deletion.

Scheduling a second notification if first is ignored in swift (or completing any action if notification is ignored)

So I have an app currently on the app store that schedules 10 notifications in advance assuming you miss one you will still get a second chance or ten. Now before you think I will be bothering the person, the notification is very important to the functionality of the app and really is the main purpose. The app was built for iOS 7 so at that time there was no "handleActionWithIdentifier" which can, from my understanding, complete actions for the app even if it is closed depending on the users response to the notification. This update was very helpful for the app as it eliminates part of my problem of having to open the app to respond to the notification (the notifications ask the user a question and depending on the answer, completes something).
The problem that remains is detecting if the notification was missed, how would I make another notification appear, for example the next day, if the notification is dismissed or ignored. I have searched this on google and stack overflow and from my understanding all previous questions have been asking how to detect if the notification was missed one the app is opened which I do not need.
At this point, I can properly run code if the user responds to the notification by pressing one of the options on the notification by this :
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
var userInfo = [NSObject: AnyObject]()
userInfo["text"] = responseInfo[UIUserNotificationActionResponseTypedTextKey]
NSNotificationCenter.defaultCenter().postNotificationName("text", object: nil, userInfo: userInfo)
print(userInfo)
completionHandler()
}
as of right now, I am just taking textfield input and printing it but I could launch a second notification if I wanted. Is there a method to detecting when a notification is missed and scheduling another notification?
There is always a chance that it is still not possible to do what I want and I would just schedule 10 notifications in advance which seems sloppy and does not let me make the response as iterative.
TLDR; how do I detect and run code if a local notification is missed WITHOUT opening the app
BTW: if you have answers, swift is the preferred language
You can use a mixture of Background Fetch and Some kind of timestamp test.
For instance:
When you schedule a notification you can keep some logic that would let you track if that notification was ignored or not. Maybe keep some data in NSUserDefaults holding which was the last Notification sent and when it should be launched by the O.S.
One way could be to check for that timestamp:
If you launch this test after the moment in which it was supposed to launch (and maybe a bit late, just in case the user see it but is still not ready to answer) and you haven't still marked it as not ignored, then the user may have ignored or missed your notification.
This test should be able to be used in your AppDelegate.
Then, enable Background Fetch capability in Background Modes.
This will give some CPU time to your app (when iOS thinks is a good
time for that) and you can seize the opportunity ;-).
For being able to do that you will need to add proper function into your AppDelegate implementation:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// your code
}
In this function's body, run your "test for ignored notification" and schedule new notifications if needed.
Don't forget to call completionHandler as soon as you finish your test!

How to create background services for local notification?

I am trying to create local notifications for my iOS application based on JSON new data.
I have created web services and parsing some datas and store into plist as a string at first time.
I want to parse JSON at every n minutes once and compare with plist stored data for anything newly arrived datas or not.
If anything newly arrived I want to show notification.
Those process want to do application active and background both times without any hanging.
Thanks,
iOS does not support these kind of background service. The reason being that they drain the battery and therefor give the user a bad experience. You might want to implement it serverside.
Apple only allows background running for apps that fall the in following categories: VOIP, audio streaming, location and accessory (bluetooth).
If you want to update data from the server in the background, you basically have 2 options:
Use background fetch. The system will launch your app into the background in specific intervals (which are not entirely under your control!) and give it the chance to download (have a look at this post for a good intro).
Use (silent) push notifications. This of course requires work on the backend-side.
Which one you should use depends on things like
Whether you have control over the backend (if not, you can't send push notifications)
How often the data is updated. If it's updated very often, background fetch might be ok. If it's updated very infrequently or irregularly, then push might be superior.
You can use Silent Push Notifications,if Push notification serve your purpose.It doesn't come in notification tray.
1.As soon as when notification comes , Below method is called,overide this method
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.NewData)
NSLog("Download From Remote Notification%#",userInfo)
}
2.Enable Remote notification
No user Interaction is needed in silent push notification
Here is good article which explains step by step guide
http://www.g8production.com/post/72656082173/ios7-multitasking-silent-notifications

Why is didReceiveRemoteNotification not called but didReceiveRemoteNotification:fetchCompletionHandler called when my app is in the foreground?

If I override
override func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("hey)
}
I successfully have the method called with the app in the foreground when I send a push notification.
If I override
override func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("hey")
}
I don't get any call to the method when sending a notification with the app in the foreground. Why does the first one work, but the second one doesn't when the app is in the foreground?
Note that I am only implementing one of these at a time. Not both at the same time.
You should use the callback version unless you need to support ios<7 (when it was introduced). As you are using Swift I expect that is not the case.
The older method goes back to ios3 and is deprecated in all but name:
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler: method instead of this one whenever possible. If your delegate implements both methods, the app object calls the application:didReceiveRemoteNotification:fetchCompletionHandler: method.
The older version will also give different results depending on whether the app is live (foreground or background) or launches from a cold start. In the latter case, it will not get called, and you will need to intercept the launchOptions dict on didFinishLaunchingWithOptions to get at the infoDict:
If the app is not running when a remote notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary. The app does not call this method to handle that remote notification.
Use the callback version. It works for all cases. You don't have to use the completion handler/block, in which case the effect is the same (well, more consistent with the newer method).
update
sorry, Apple says you do have to call the completion block "as soon as possible" - you have 30 seconds to do so before the OS gives up on you. This might be the source of your warning.
As soon as you finish processing the notification, you must call the block in the handler parameter or your app will be terminated. Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block. In practice, you should call the handler block as soon as you are done processing the notification.
So call the completion block:
completionHandler(UIBackgroundFetchResult.NoData)
I have been using this method without calling that completion block and haven't experienced any problems, but i will add one now just to be safe. Apple suggests that if you don't, your app won't get foregrounded but I have not seen that in practice.
Did you register at least one UIUserNotificationType with UIApplication:registerUserNotificationSettings: ?
If you do not register for badge, sound, or alert then you can only receive silent notifications, which are only delivered with a FetchCompletionHandler.

Execute code in background when push notification is received

I'm trying to find out what is actually possible on iOS when it comes to background tasks.
I have an app which is running in the background and tracking location changes on the device.
Now, is it possible to send a push notification to the device and have the device send the current location to a server without needing the user to open the app so it runs in the foreground?
I know this question is a bit old but I'm answering for those who, like me, arrived here long after the question was asked.
Now, is it possible to send a push notification to the device and have the device send the current location to a server without needing the user to open the app so it runs in the foreground?
Yes. You can now do that. I'm currently doing something pretty similar in my app. There are some other SO questions that now correctly state this. This is one
Basically, you have to enabled Background Execution for Remote Notifications. You can do this in XCode by going to your app's target. Open the Capabilities tab enabling the Background Modes feature and checking the Remote Notifications item in the checklist. (I'm assuming you already have enabled the Push Notifications feature).
With this the code you use to handle notifications in foreground will also serve you in background as
the application:didReceiveRemoteNotification:fetchCompletionHandler method will be called while your app is in background.
Here's a sample code in Swift 3.0:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
You may wanna check out this SO question (and accepted answer) about how to handle network request in background. Background request not execute Alamofire Swift
Check out the docs about Background Execution. Particularly the section about Push Notifications
Unfortunately I don't think so. When your app is in a suspended (freezed) state, push notifications are managed by SO, users need to reopen the app. They other way around is to create local notification for significant changes, when the notif arrives your app has a minimum amount of time, it will be not enough to post data, but you can study something. I will suggest you to read this question it talks about bluetooth and geolocation link
It's impossible. This OS has one principle —— user should know what you(your app) have done. When your app is suspended,your push message will be received by the notification center.The only way let your app know this thing happened is to launch your app through the notification center.so.....

Resources