iPhone AVPlayer - Execute Code in Background - iphone

I am trying to stream a remote mp3 using AVPlayer.
I have set up the Audio Session, and added the Plays Audio In Background to my info.plist file.
I am running this code:
self.timeObserver = [self->player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:nil usingBlock:^(CMTime time) {
[self updateControls];
}];
to add a time observer, that calls updateControls every second.
Thing is, when the sound buffer is low, the player just pauses, and this code in the background is stopped, so I have to manually press play in the app again. (and if I pause the player, this code doesn't run either)
Am I doing anything wrong? How can I run a piece of code the whole time in the background without interruptions?

You can't run arbitrary code in the background indefinitely. You can keep the audio playing, but you shouldn't be expecting to update your UI if you're not the frontmost app. You can update the UI when your app moves back into the foreground.
As long as you set your AVAudioSession properly and make it active, and you have the UIBackgroundModes set, you should be good to go on the audio front.
see http://developer.apple.com/library/iOS/#documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Configuration/Configuration.html

You will need to envelope your background code like this:
__block UIBackgroundTaskIdentifier bgTask = nil;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
[[UIApplication sharedApplication] endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//Your bg code here
[[UIApplication sharedApplication] endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;

Related

File download fails with AFNetworking and other frameworks. wifi goes to sleep automatically - objective c

I'm downloading files with AFNetworking framework. File downloads well in foreground mode. But when I put my app to background, WiFi goes to sleep automatically after 10 minutes, by iOS, and my AFNetworking request loses connection. In my AppDelegate I have this code to run background task:
-(void) runBackgroundTask
{
if (bgTaskId!=UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
UIBackgroundTaskIdentifier newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
[self runBackgroundTask];
}];
bgTaskId = newTaskId;
}
How disable automatic WiFi sleep? If I run music on my app and downloading file - everything is OK. WiFi doesn't disable.
How I can solve this problem?

AVAssetWriter fails once App goes in background

I am working on iOS app in which i am creating video from images. I am using AVAssetWriter to achieve this. Everything works fine. But When app goes in background and switched back, the video writing fails. AVAssetWriter's finishWritingWithCompletionHandler is not getting called when i switch back to app.
May be duplicate of AVAssetWriter fails when Application enters Background during Rendering , but i am not getting any help from there.
Any idea for this?
Thanks
This answer is based on the assumption that you want the video to continue rendering while in the background.
I fixed this in my app doing by asking the OS to grant the app background task permisions (for a limited amount of time). This answer might help you too
iOS generating a video in the background task
#property (nonatomic,assign) UIBackgroundTaskIdentifier __block backgroundRenderingID;
UIApplication *app = [UIApplication sharedApplication];
_backgroundRenderingID = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:_backgroundRenderingID];
_backgroundRenderingID = UIBackgroundTaskInvalid;
}];
Don't forget to let go once you are done!
[[UIApplication sharedApplication] endBackgroundTask:_backgroundRenderingID];

Network disconnect issue when iOS screen locks

In iOS 5 When Application Enter background wi-fi connection is lost.
But I want to use wi-fi connection for the next 4-5 minutes before the device sleeps as some tasks can be performed within 4-5 minutes of application enter background.
I think this can be accomplished by using beginBackgroundTaskWithExpirationHandler:, but i am not able to solve the problem
just disable iPhone to go to sleep mode
-(void) sleepModeDisable{
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}
call this function every 10 second, this might help u
The way I handle this is to use beginBackgroundTaskWithExpirationHandler for every network request I'm sending.
This way I make sure that all my networking will completed even if my app moved to background.
I'm usually using one singleton object to handle all network request, so before the request is sent I call
- (void)startBackgroundTask
{
// ask for extra time if this is called when app go to suspended
UIApplication *application = [UIApplication sharedApplication];
_bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[application endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
}];
}
And after I get a response (success/failure) or if I canceled the request, I call
- (void)stopBackgroudTask
{
UIApplication *app = [UIApplication sharedApplication];
if (_bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
}
}
* Don't forget to define UIBackgroundTaskIdentifier *_bgTask;
Also if you are planning to make a massive use of Wi-Fi you should set the Application uses Wi-Fi key in your plist file to YES, otherwise your Wi-Fi will be shut done after 30 minutes even if your app is running.
No rocket science here, this is intended behavior in iOS that to save battery the Wi-Fi shuts off when phone is locked UNLESS you tell iOS that your app needs a persistant Wi-Fi, then it wont close it for you when your app is running.
For that just add UIRequiresPersistentWiFi to your info.plist and mark it YES
Documentation

How to know if a task is executing in background

In my app I'm downloading lots of images on a method.
I'm using a
downloadTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:downloadTask];
downloadTask = UIBackgroundTaskInvalid;
}];
This is working fine, if I press the home or sleep button, the images continue downloading.
I'm showing the progress in a UIProgressView inside an UIAlertView, and when the percent is 100% the alertView is dissmised and I change the viewController to other where I show the donwloaded images.
But I only want this to happen if the app is really active at the moment the download finish.
I have been looking at the app state and while it's downloading with the screen off.
[UIApplication sharedApplication].applicationState
the state is UIApplicationStateActive during all the donwload
How can I can know if the downloading is happening with the screen off or on?
EDITED AFTER ACCEPTING THE ANSWER:
I just discovered, if I tap the home button, the app enters in UIApplicationStateBackground, if I tap the wake/sleep it enters in UIApplicationStateInactive
Following the approach of the correct answer, my app contines donwloading in both cases.
The screen is off in two states (apart from when the app has not been even opened):
suspended : in this case you don't have to worry because the download won't procede until the app gets active again; It will enter this state on
background : it's in this state for a limited amount of time before going in suspend, and the screen is already off in this moment. Here you may want to check then whether to do all the things you said or not, because in this state code can be still executed. In this state the app status is UIApplicationStateBackground, so you could just perform a check like this:
You probably want to check whether the app is in background execution in order to achieve the result. Just like this:
if([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) {
// Do stuff
}
If it's in background, so the screen is off.
UPDATE: after few test, what I figured out is that the behaviour you are expieriencing is probably due to the execution of the download on the main thread.
You should send the download on (for instance) the global queue. This way the application will enter the background state as expected:
....
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bti];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doBackgroundStuff];
});
....
This way, if the app is put on background while the download is in progress, the application state will turn into UIApplicationStateBackground, and then you can check it as I wrote initially. If you are doing UI updates during the progress remember to send them back to the main thread (because the download is now on a different one).
You can check whether your app is running in the background or not by setting a flag in the designated application delegate methodsapplicationDidEnterBackground: and applicationWillEnterForeground:. Example:
- (void)applicationDidEnterBackground:(UIApplication *)application
_applicationRunsInForeground = NO;
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
_applicationRunsInForeground = YES;
}
If you don't want to have this _applicationRunsInForeground flag inside your application delegate, you could observe the delegate's NSNotifications in your viewcontroller class instead (UIApplicationWillEnterForegroundNotification and UIApplicationDidEnterBackgroundNotification).

How to handle network in background State

I am sending email using SMTP Implementation .Now i am switching to another app network to be suspend. How to handle network not to be suspended.
Regards,
Arunkumar.P
Login to iOS Dev Center, and search "background task", you'll find the document you need.
To be more clear, every time your app is to start a task that may take some time to finish and should be alive even in the background, you should declare a UIBackgroundTaskIdentifier before such a task starts, and tell the iOS that this is the task that needs to run in the background. And you also have to make sure that when your task ends, you should always tell iOS that it's finished and no more special background permission is needed.
Your code should look like this:
//right before your critical task starts
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
//immediately after your critical task finishes
if (newTaskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask: newTaskId];
}