I am trying to get my app to continue uploading to Dropbox once it's put into the background, but I can't seem to figure out why it doesn't work.
Apple's docs give 2 ways to do this which I understand as:
1. Do something within a given time frame
2. Do one of our pre-ordained activities
Given that the Dropbox API doesn't expose an NSURLSession and Apple's closest explanation in the docs is geared towards "downloading" in the background, I assumed that the correct way is to go for approach 1, so I wrapped my code in the block Apple suggested, but once I close the app it stops.
__block UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:#"UploadImages" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
for (PHAsset *currentImage in images) {
[self.imageManager requestImageDataForAsset:currentImage options:opts resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
// set some variables...and then call Dropbox upload
[self.restClient uploadFile:fileName toPath:destPath withParentRev:nil fromPath:filePath];
}
}
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
I've also requested that the app allows network activity. It doesn't seem to make a difference
I'm pretty new to iOS so any guidance would be helpful. Maybe I'm missing something obvious.
Related
I have some NSOperations that are started regularly in my application. They should complete even when the the application is put to background. For this, I'm using the beginBackgroundTaskWithExpirationHandler method.
Am I supposed to use the beginBackgroundTaskWithExpirationHandler/ endBackgroundTask: every time I start my task even if the app is not going to background? Or am I supposed the call the begin/end methods only when I detected a UIApplicationDidEnterBackgroundNotification?
Option 1: Use background task every time
/**
* This method is called regularly from a NSTimer
*/
- (void)processData
{
__block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
}];
NSOperation *operation = ...
[self.queue addOperation:operation];
operation.completionBlock = ^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
};
}
Option 2: Use background task only when the application is about to go to background
/**
* This method is called regularly from a NSTimer
*/
- (void)processData
{
NSOperation *operation = ...
[self.queue addOperation:operation];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
__block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:#"EnterBackgroundFlushTask" expirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
}];
// wait for all operations to complete and then
// let UIApplication know that we are done
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
}
Answering my own question. From the Apple Docs:
You do not need to wait until your app moves to the background to
designate background tasks. A more useful design is to call the
beginBackgroundTaskWithName:expirationHandler: or
beginBackgroundTaskWithExpirationHandler: method before starting a
task and call the endBackgroundTask: method as soon as you finish. You
can even follow this pattern while your app is executing in the
foreground.
Other Apple API reference:
You should call this method at times where leaving a task unfinished might be detrimental to your app’s user experience.
You can call this method at any point in your app’s execution.
Option2 is correct option.Here is code from Apple document for your reference.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[self processData];
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
Apple developer Guide
I have added data fetching operations to NSOperationQueue .During the process, I just put the device to sleep mode and the process gets stopped. I surfed stack overflow an get some basic ideas.I need help to continue my fetching process without any interruption when device moves to sleep mode.Help appreciated !!
NSManagedObjectContext *managedObjectContext=((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;
NSOperationQueue *downLoadQueue=((AppDelegate *)[[UIApplication sharedApplication] delegate]).downloadqueue;
//Fetch operation
if([fetchqueue count]>0)
{
Queue *queue=[fetchqueue objectAtIndex:0];
queue.status=#"INP";
[managedObjectContext performBlockAndWait:^{
NSError * error = nil;
if (![managedObjectContext save:&error]){
NSLog(#"Unresolved error while loading3");
}
}];
DownloadOperation *downloadOp=[[DownloadOperation alloc]init];
downloadOp.queue=queue;
[downLoadQueue addOperation:downloadOp];
}
}
The downLoadQueue started its execution. It is fetching data from server meanwhile the device goes to sleep and the execution stops. I don't know how to continue in this block applicationDidEnterBackground. How can I get my lengthy downloading process during sleep mode?
Also tried this one..But the operation was not resumed.
//code follows
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSOperationQueue *downLoadQueue;
downLoadQueue=((AppDelegate *)[[UIApplication sharedApplication] delegate]).downloadqueue;
[downLoadQueue waitUntilAllOperationsAreFinished];
});
}
Please suggest any ideas.
I think the only way to do this is background task. Take a look at apple docs about this. There are also a lot of answers on stackowerflow how to implemet such feature.
I think in your case you can try next code to execute NSOperations a in backgraund task:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
//Start your NSOperationQueue if it's not executing
//Lock current thread while operations are executing
[queue waitUntilAllOperationsAreFinished];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
I have been using https://github.com/Jawbone/UPPlatform_iOS_SDK for a while now
and getting the user's daily steps.
I wanted to pull data from the Jawbone API when the app is in background state.
I have followed this tutorial : http://www.devfright.com/ios-7-background-app-refresh-tutorial/
To call this method :
[UPMoveAPI getMovesWithLimit:10U completion:^(NSArray *moves, UPURLResponse *response, NSError *error) {
NSLog(#"This is not getting executed in background");
}];
The jawbone session is successfully verified and seems that my session is active.
But I get no response and the above NSLog doesn't get executed in background.
Please I have tried contacting Jawbone support, seems that they are not replying back.
Anyone experienced the same, please help.
Try below code options:
Option-1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[UPMoveAPI getMovesWithLimit:10U completion:^(NSArray *moves, UPURLResponse *response, NSError *error) {
NSLog(#"This is not getting executed in background");
}];
}
Option-2
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
Also note that you require to add UIBackgroundModes in info.plist
Hope this helps.
I am working on one application in which it requires to merge more than one videos. I am using AVExportSession to export merged video. I am also displaying progress bar for exporting video. It is running correctly.
The issue occurs when we lock the screen or put application in background mode. This time if exporting is in process, it immediately fails after putting application in background mode.
I have also tried to use background task. Check below code.
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) {
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier background_task; /
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//START EXPORT SESSION
[exporter exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
});
}];
NSLog(#"Running in the background!");
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
}
}
But this does not seem to work. What am I doing wrong? Any help would be appreciated.
I know it is possible to run an AVExportSession in the background as I found many apps in the app store that can do this.
Thanks in advance.
replace this code for [self exportDidFinish:exporter];
[self performSelectorOnMainThread:#selector(exportDidFinish:) withObject:exporter waitUntilDone:YES];
I want to upload some files which should continue even if the application goes into background.
Currently I am retrieving the files from the DB and than adding it to the Queue via NSOperation which is then starts the upload procedure.
All the files should be uploaded even if the app goes to background or foreground.
Below is the code for single task can anyone give me a hint how we can make it to work for uploading many files.
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;
}];
Why not try doing this? .. I haven't yet tried it out, I'll post an update after attempting this
UIApplication* application = [UIApplication sharedApplication];
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
// Bring up your NSOperation queue instance here and block this thread until it is complete
[queue waitUntilAllOperationsAreFinished];
[application endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
also ensure that you have a way to cancel all these long standing operation in the background
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[queue cancelAllOperations];
[application endBackgroundTask:endSessionTask];
bgTask = UIBackgroundTaskInvalid;
}];
Apple allows background execution if your app follows and satisfy the necessary condition.
plese refer here