I'm trying to run an NSTimer task:
timerUploadData = NSTimer.scheduledTimerWithTimeInterval(60 * 1, target: self, selector: "uploadData", userInfo: nil, repeats: true)
But it only work when we have the app in background, but I wan't to still run this even if the app is stopped by doing double tap on home and slide the app to the top to kill it. How to do this ?
If the user kills the app, it is no longer running, therefore your code is no longer running. There is no such state that your code/app can be in where this is possible.
I think you should read the app life cycle document.
Related
Hello I am developing the Application in which i need to send Data in Http request every 10 seconds. it's working fine when app is in running state but it will stop as soon as it will goes in background or inactive state.
Your app need to support a couple of things.
If your app can have the background-running capability then you can do a couple of things.
To run periodically you will need a Timer (NSTimer).
You will need a method which will execute the HTTP request.
Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(callWebservice), userInfo: nil, repeats: true)
func callWebservice() {
// Handle response
}
Also please refer : https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
I've read many many articles, read many StackOverflow posts and tried different solutions, but I can't get it to work.
For an app that communicates with bluetooth headsets, the user must be able to start/stop a stopwatch when the user presses a button on the headset. When this button is pressed I receive a bluetooth event and start the stopwatch (receiving this bluetooth event in the background is not a problem). When the stopwatch is started I use the AVSpeechSynthesizer to speak the text 'Stopwatch started'. Now comes my problem: I want to have a text to speech every minute, speaking the amount of minutes that elapsed. But also when the app is in the background...
I've read about solutions like this:
var bgTask = UIBackgroundTaskIdentifier()
bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
UIApplication.shared.endBackgroundTask(bgTask)
})
let timer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(notificationReceived), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.defaultRunLoopMode)
It did work, but I can't find anything about how stable this code is on production (when the app is downloaded from the App Store). Also scheduled local notifications can not trigger any code when the app is in the background. Even the property postUtteranceDelay of AVSpeechUtterance seems unstable. I set the property to 460 seconds, but the text was spoken after a random 56 seconds...
I turned on almost all the background modes for my app.
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>bluetooth-central</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
Other people suggest to make a silent audio track. But it seems that apps using that kind of 'silent tracks' are being refused by the Apple Review team.
What depresses me the most, is that apps like Runkeeper and Seconds Interval Timer are able to do his. Even when I turn on flight mode and disable all settings (like push, motion sensing) from the apps. So, why can't I find a working solution...?
Does anyone have a suggestion where to start?
I'd like to prevent iOS from killing my app after a few minutes.
I've read this thread here on SO: Prevent iOS from killing my app after 3 minutes . It says that if I have no backgroundtasks longer than 3 minutes my app wont be killed. Can someone verify that this is true? Because my background-task is not running longer than 3 minutes and even though my app gets killed after this time.
My background-task is a timer that updates a widget. Heres some code:
self.backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.endBackgroundTask()
//endBackGroundTask looks like this
UIApplication.shared.endBackgroundTask(self.backgroundTask)
self.backgroundTask = UIBackgroundTaskInvalid
//
}
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(self.updateTimer)), userInfo: nil, repeats: true)
.
// at the beginning of the class
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
.
// in viewWillDisappear
self.timer.invalidate()
if self.backgroundTask != UIBackgroundTaskInvalid {
self.endBackgroundTask()
}
You need to structure your app so that it doesn't require continual execution in the background. As I understand it, your app shows a count down timer and can show the same count down timer in a Today Widget. The approach I would use is follows:
Store the "end date" for the timer in user defaults to share with your widget
When your app is in the foreground, use a Timer to periodically update your UI
When your Widget is being displayed use a Timer in the widget to periodically update its UI
When your app moves to the background, schedule a local notification for the expiration time
When your app moves back to the foreground, you can cancel that scheduled notification if it hasn't yet fired.
Support app restoration for those cases where your app is legitimately terminated (e.g. due to memory pressure or being suspended for a long period)
If you do this then you never need to call beginBackgroundTask. If you do call beginBackgroundTask and don't call endBackgroundTask within 3 minutes of entering the background, then your app will be terminated, even if you aren't using any CPU.
Short answer: You can't run a background task for longer than 3 minutes unless you are a turn-by-turn navigation app or an audio player. Apple doesn't allow it by design.
Your background task is a timer that is running longer than 3 minutes. So your app is correctly being killed. Consider it confirmed as that is Apple's design.
It's not what your timer is executing that is killing the app, it's the timer itself.
You can read up on Apple's Documentation for more information.
Always try to avoid doing any background work unless doing so improves the overall user experience. An app might move to the background because the user launched a different app or because the user locked the device and is not using it right now. In both situations, the user is signaling that your app does not need to be doing any meaningful work right now. Continuing to run in such conditions will only drain the device’s battery and might lead the user to force quit your app altogether. So be mindful about the work you do in the background and avoid it when you can.
I have a framework that returns a ViewController to my app upon request.
This view controller contains a QR code that is subjected to change after a certain period of time - say 3 days.
I would like to call a method contained inside the framework after 3 days so that the changed/updated QR is readily available even if the user is not using the app actively. When user opens the app - the updated QR is there!
For that, I have used below in my ViewController inside the framework - (from tutorial link)
//MARK:- Add Timer to run QR Logic after 5 seconds
let date = Date().addingTimeInterval(5)
let timer = Timer(fireAt: date, interval: 0, target: self, selector: #selector(QrUIViewController.performQrFetchLogic), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
This piece of code works perfectly when app is active/background. Is it possible, and how to achieve this even if the app is killed?
PS: I read Jobscheduler and AlarmManager will work for Android - is there something similar to these in iOS?
The best way to achieve this is probably using a scheduled Local Notification.
You schedule local notification for some time in the future and then afterwards react to it. This is the case both for when the app is active, in background or inactive.
Remember that notifications do not fire if the user kills your app.
I am making an app that helps people with tracking down the working intervals.
What I need is the timer should run at least 30 minutes regardless of the app is in foreground or background.
func startFocus() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(Pomodoro.focusIntervalCounter), userInfo: nil, repeats: true)
}
func focusIntervalCounter() {
dynamic_focusIntervalSecond -= 1
focusDelegate?.updatingFocusCountingDown(timeStamp: seconds2Timestamp(intSeconds: dynamic_focusIntervalSecond), secondLeft: dynamic_focusIntervalSecond)
if dynamic_focusIntervalSecond == 0 {
timer.invalidate()
focusDelegate?.focusCountingDowndid(end: true)
}
}
focusIntervalCounter() should invalid the timer when the `dynamic_focusIntervalSecond` is 0.
It works fine when the program is in the foreground, but after the screen is shut, the timer just works a little while and stop.
Is this any approach to continue the timer's counting?
Thanks in advance.
No, you can run background tasks for up to 5 minutes, use the background update functionality to trigger app refresh, or use notifications to trigger background actions. There is no way in iOS to guarantee that any code will be run consistently in the background after 30 minutes. Local notifications will enable your code to run after the user selects an action in a notification. Silent push notifications can run some code in the background open receipt, but require an internet connection and are not guaranteed to be delivered.
See this question for more info:
iOS Timer in the background
No, You cannot run Timers in background mode. You can create a UIBackgroundTaskIdentifier which will give you 180sec as i have observed, i'm not sure it might vary with OS version.
You can try scheduling local notifications for 30 mins.
You can enable back ground modes if you're using push notification, Airplay, Location, VOIP apps, Bluetooth, News stand, Background fetch, for more details read this apple developer document BackgroundExecution
Some things are not possible in background, Have you switched your project to enable the background modes? You can reed more about it here