I have been facing a issue that my app doesnt run background for more than 10 mins , I have implemented background task which will fetch notifications instantly.
my application background task stops after 10 mins, I have already refereed solutions of this and this , but it doesnt seem helpful
my code is as follows
-(void)methodBGTask :(UIApplication *)application{
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4
if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(methodGetNotificatioin) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
}
}
-(void)methodGetNotificatioin{
//retrieve notifications from service
}
Thanks In advance
This is normal. You are not supposed to run timers in the background. On iOS7 and above, you should be using background fetch mode to fetch data (or do it properly, using push).
Read here for more information on iOS7 background modes.
Note, that on iOS7 and above, background tasks are even shorter (~30 seconds) rather than 10 minutes, so you are even less encouraged to use that API for such work.
If I'm not mistaken or not misunderstanding your question, this is expected behaviour. Background tasks are time limited so that one app doesn't run indefinitely and consume resources like battery power and cellular data.
There are different types of background modes, some perform a set task and suspend when complete or timed out, others run periodically.
You're likely looking to implement background fetch, wherein the OS will periodically wake your app and allow it to check for new content and perform a quick data fetch to get the latest data from your server.
Background fetch can be triggered by a push notification that has the "content-available" flag set in its payload. The OS will be selective in scheduling background fetches for apps and will often coalesce them together to be more efficient. The OS will also learn when users run your app and try to schedule background fetches before the time a user opens your app so that the latest data is available.
You should use Push Notifications instead fetching them every 5 minutes. It's will work on the fly and will not drain the battery.
Related
I am making an app that provides functionality to fetch data every hour. It fetches data even when the app terminates. How can I implement this functionality?
After a lot searching I found background fetching using performFetchWithCompletionHandler. Will this function work even if my app terminates? What I mean is if my app is in closed or terminated state, can I call this function automatically?
You can't do anything if your app is in terminated state. Apple is not allowing anything (except receiving notification) in terminated or closed state.
You are also restricted for background execution also.
You can perform specific kind of task in background mode like : Location update,Music playing, VOIP, finite length task, Newsstand downloads, etc. You can refer apple documentation for more details about background execution.
Hope this will help :)
Once I needed this same when I was working on some project, unfortunately I didn't
find any solution for it.
You can run a task when your app is in Background state(that too with limited services) but apple doesn't allow to run a task when app is Terminated
Please go through the link.
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
and this is for background running.
Sending Latitude and Longitude to Server when app is in background
Your app is terminated once it will not do any kind of task related to it.
Apple Doesn't support it.
You can not call Functions when your app is not running.
So it's not possible Due to apple rules.
performFetchWithCompletionHandler is only work when your app is running if your application is terminated it will not perform any kind of task.
From what i have experienced:
First of all the timer will stop when the app goes to the background to stop fast battery drainage and expand the lifetime of the battery even to save network bundles quota consumption while you are not actively using the app.
You can do background fetch tasks by adding the following in the AppDelagate "as you mentioned":
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
//Do whatever you need
//This will keep running for max 3 mins
}
But the same is for background fetch tasks. You have got maximum 3 min of background activity except for Locations services, Audio playing, VOIP and some other tasks.
I really don't know the use and the functionality of the app and why do you need to grab data from the server every 1hr if the app is already closed and the user is not concerned about seeing the updated data.
But if this data is important to be updated every hour and need to notify the user with the updates "for instance checking the status of a certain event on the server, like making a chat app and the user received a message".
Then it is better to send a remote push notification to the user from the server upon a certain event taking place and this will make the user get the app again on the foreground and the app will start fetching the updated data "in my case here the message".
you can find location in app terminated state, after significantly change in location like about 500 meter.
here is working example
http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended
but what I am stuck at is post location through webservice.
#Jack.Right you can call the method after every 1 hour so use NSTimeinterval it would be helpful!!
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(methodRunAfterBackground) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
Ok , im not getting answers about this. :(
Multipeer Connectivity audio streaming stop work on background
What about this?
i'm trying to run this code on background.
- (void)applicationDidEnterBackground:(UIApplication *)application {
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSTimer *aTimer = [NSTimer timerWithTimeInterval:3
target:self
selector:#selector(showInformation)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop]
addTimer:aTimer
forMode:NSDefaultRunLoopMode];
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
Obviously i ihave this function defined on the same scope
- (void) showInformation {
NSLog(#"showInformation is called.");
}
But when i put the app on background, the interval message, stop work and when i come back to the foreground continue working ........
This means is not running on the background?.
Is this possible? or am I trying to do something stupidly impossible?
I really appreciate some help.
Thanks a lot.
Regardless your code works or not, your background task will be terminated after a while (>10 minutes) by iOS unless the UIBackgroundModes is set in your app (VOIP, Location service, Audio ..).
For more about Background Execution check Background Execution and Multitasking.
Another option in iOS7 is using Background Fetch, but you don't have control over time (there is a smart Timer used by the iOS).
For better understanding check Raywenderlich's Background Modes in iOS Tutorial.
And if you need something working check the below SO posts:
How do I get a background location update every n minutes in my iOS application?
Running iOS App in background for more than 10 minutes
Will iOS launch my app into the background if it was force-quit by the user?
For the bounty, I am not interested in GPS or audio background modes as the former uses too much of the battery and the latter prevents any other audio from being used, otherwise facing audio interruption, thus ending background processes. I will need a way to be continuously processing in the background, so background modes that trigger occasionally are also out of the question.
If there is some way to run the application in the background, even by ignoring Apple's rules, I am interested in trying it. If the answer is VOIP, I am unsure where to begin the implementation, as all of my research has come up too high level or as a failure. How will my application be able to run in the background using the VOIP background mode. Without any added code, the application refuses to run in the background.
I know that with iOS 7, background modes have changed again. I would like to be able to run my application (that will never need to be approved on the iOS App Store) in the background. I would also like to be able to stop execution in the background until a specific time in the future.
For example, I would like it to run a process for 15 minutes, schedule the next task and then sleep until that time. For now, I've had to run a silent track in the background for background processing, but I would like to be able to have the application truly sleep during that time - also, playing real music or making a phone call are "handy features" of the iPhone and I don't like losing them.
I know there is also GPS, but that consumes an enormous amount of battery. The other background modes don't seem to give full control of background processing and timing to the application and leave a large portion of the timing and execution duration to the OS.
What I need is to be able to have my application process in the background for minutes at a time and then sleep until a fairly specific interval and continue processing. Is this possible with a better approach than I am currently using?
I've seen that VOIP used to be a possibility, but I'm not sure that it will work, as I don't need the application to run one simple task in the background, but rather to continue whatever was running in the foreground before the application was pushed to the background. Also, individual tasks could take upwards of 1 hour to complete, so they won't be able to transfer when the background task expires. All of my assumptions are based off this thread.
Edit: There seems to be a terrible drop off rate with this method. At random, the recursion will seemingly fail for seemingly no reason (maybe a system timeout on execution?). If I place the recursion before ending the background task, the OS kills my application, but if I put it after, it occasionally seems to stop the background tasks at some point. I have seen it stop in the middle of my "allotted background time", as well.
In short, the below method does seem to run indefinitely, but not infinitely. Is there either a way to make the runtime guaranteed to be infinite or another solution?
It seems that using VOIP was leagues easier than I had first thought.
All that is required to run my application indefinitely (unfortunately sleeping is not an option) is to add voip to the selected Background Modes, either in the plist or in Target's Capabilities. After that, adding and running this code once, in an object that is never deallocated (your AppDelegate works nicely here), will allow for infinite background processing time:
- (void)infiniteBackgroundLoop
{
__block UIApplication *applicationBlockReference = [UIApplication sharedApplication];
__block AppDelegate *appDelegateBlockReference = self;
__block UIBackgroundTaskIdentifier backgroundTask = [applicationBlockReference beginBackgroundTaskWithExpirationHandler:^
{
[applicationBlockReference endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
[appDelegateBlockReference infiniteBackgroundLoop];
}];
}
In order to allow sleeping indefinitely, add a break to the recursion.
I used background fetch to achieve something similar.
You can use this to keep your app active in the background.
I have the a demo, see if it helps you:
Add these properties to your .h file -
#property (nonatomic, strong) NSTimer *updateTimer;
#property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
Now suppose you have a action on button --> btnStartClicked then your method would be like :
-(IBAction)btnStartClicked:(UIButton *)sender {
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(calculateNextNumber)
userInfo:nil
repeats:YES];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background handler called. Not running background tasks anymore.");
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
}
-(void)calculateNextNumber{
#autoreleasepool {
// this will be executed no matter app is in foreground or background
}
}
and if you need to stop it use this method,
- (IBAction)btnStopClicked:(UIButton *)sender {
[self.updateTimer invalidate];
self.updateTimer = nil;
if (self.backgroundTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
i = 0;
}
We also played with background modes in our app, and I check all solution that found, and can say that there is only one way to stay active in background and is not "VOIP", because "VOIP" gives your app wake-up every 5-6 minutes not infinity run.
In documentation about setKeepAliveTimeout:handler: you can see that this method will call handler block at minimum every 600 second, and block has a maximum of 10 seconds to perform any needed tasks and exit.
To clean this you can add NSLog(#"time remain: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]); to your infiniteBackgroundLoop implementation. Because second and next call beginBackgroundTaskWithExpirationHandler not get same time of background run as first call.
Another working way is Location Manager, yes is bad because use lot of battery but is get you that you want - app newer stop.
The implementation can be easily found there
You could use background fetch and set the regresh rate to a short NSTimeInterval.
In your didFinishLaunchingWithOptions: try to add:
[[UIApplication sharedApplication] setMinimumBackgroundFetch:1];
I haven't tested this, let me know if this could be a starting point.
I have created a sample code to download a file from network repeatedly(every 30 secs or so). In iOS 7 using Background transfer services with NSURLSession
I followed this tutorial http://mobile.tutsplus.com/tutorials/iphone/ios-7-sdk-background-transfer-service/
and added a timer like this to repeat it.
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
mute = [NSTimer scheduledTimerWithTimeInterval:30.0f
target:self
selector:#selector(startDownload)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:mute forMode:NSRunLoopCommonModes];
When I run it(in background by clicking home button) in simulator and on iPad connected to the Xcode(where I can see the logs) everything works fine and it keeps downloading continuously.
But when I disconnect the iPad from the Mac and run it on the iPad in background after around 3 seconds it stops running (handleEventsForBackgroundURLSession in AppDelegate get called).
In Xcode project capabilities I have selected Background fetch as Background Modes.
What am I missing here or what have I done wrong so that it gets stop after around 3 minutes?
(According to the documentations with iOS 7 Background transfer services it should run continuously as there's no time limit in background for this.)
Thanks
Background tasks in iOS7 will only give you 30 seconds at most (dramatically down from 10 minutes). You should use the new fetch background mode instead. You should not be using a timer, but use the newly provided API to ask the OS to be woken up in regular intervals and set up your download using NSURLSession.
Background Fetch is something different. Background Fetch will wake up your app for periodic fetches of new data (typically, a < 30s network request looking for updates). This is not related to background NSURLSessions and should probably be turned off if you aren't actually using it for queuing NSURLSessionDownloadTasks or other update purposes.
From what I understand, it's possible that the behavior you are seeing is actually normal. I do not believe that background NSURLSessionDownloadTasks are guaranteed to run continuously or on any device configuration (AC vs battery, WiFi vs Cellular, etc.) You said that you disconnected from your Mac which would switch device state from charging to battery. Among other factors, that could be enough to pause transfers or decrease download limits. Unfortunately, this system appears to be very opaque to developers.
To be sure you are getting the highest priority available, make sure your discretionary property on your NSURLSessionConfiguration is set to false. Download tasks created while the app is in the background will always have this set to true, so just an FYI there.
Apple's sample code will put you on the right track: https://developer.apple.com/library/iOS/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html
Try the below steps. This worked fine for me.
In your .h
UIBackgroundTaskIdentifier bgTask;
In .m
//background task code
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
[NSTimer scheduledTimerWithTimeInterval:30.0f target:self selector:#selector(startDownload) userInfo:nil repeats:YES];
And yor method for downloading is
-(void)startDownload{
NSLog(#"will log even if in background or foreground");
}
Practically using [[UIApplication sharedApplication]beginBackgroundTaskWithExpirationHandler: ^{}]; will give you only 180 sec.Xcode provides the facility of background active app while debugging only just to ease developers.
NSURLSession download tasks are indeed not bound to time restrictions. But they are completely managed by the system. They may get postponed if the system resources are low. They are normally dialed down when there is no wifi or when the device is not plugged. The system also observes your app's use of the background transfer services and may treat it with lower priority if it detects that it abuses the feature. A background transfer every 30 seconds, is certainly considered an abuse.
I suggest dropping the use of Background Transfer Services and set up the entire thing using background fetch (which is a completely different thing btw). Just be careful if you want to reach the store, you must fall in one of the accepted uses cases for the feature to be approved for your app. If not, then there is little hope. Not sure what you are trying to do. Maybe you don't really need to have so much background activity.
I'm developing a voip app for iPad. I know there are similar questions, but none of the offered solutions have worked so far. I already know that I have to set the voip flag in the info.plist file (I used xcode for that). I have also set the "application does not run in the background" to "no" (who made up that name?!?). I also configured the socket as voip using the following two lines:
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
I read through the documentation and countless posts on SO and other forums, and there seem to be a few ways to get an app to run in the background forever. I have tried the following:
Start a long running background task, and restart the task when it fires. It was explained here on SO somewhere, but I can't find the post anymore so here is the pseudocode:
expirationHandler = ^{
if (inBackground) {
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
}
};
inBackground = true;
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// inform others to stop tasks, if you like
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyApplicationEntersBackground" object:self];
inBackground = true;
while (inBackground) {
//send a keep alive to my server
sleep(5);
}
});
The second thing I tried was to use setKeepAliveTimeout like this:
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{
//send a keep alive to my server
}];
The first one seems to work very well (note that battery life and app-store approval are of no concern to me), but only when the application runs from xcode. When I put the app on the device and run it without debugger, the app stays alive for about 3 minutes and then it dies.
The second one seems to be how it is supposed to be, but my problem with it is that it has a minimum time of ten minutes. My server closes the connection after ten minutes of inactivity and setKeepAliveTimeout seems to be a bit inaccurate, so sometimes it is off by half a second or so (I've experienced 2 seconds one time). This means that once every ten minutes there is a chance that my session to the server is closed.
I use a protocol called XIMSS, used by the Communigate Pro server platform. Most voip apps seem to use SIP, which can send keep alive packets from the server, but that is not a option for me. So how can I make sure my app always wakes in time to send a keep alive? Is there anything that has an interval smaller than ten minutes?