Background tasks not running - ios

I am trying to run some background tasks once the user quits the app.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
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
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
//System will be shutting down the app at any point in time now
}];
//Background tasks require you to use asyncrous tasks
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your tasks that your application requires
NSLOG(#"test1");
[self performSelector:#selector(checkActivityCount) withObject:nil afterDelay:3];
[application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform
background_task = UIBackgroundTaskInvalid; //Invalidate the background_task
});
}
}
}
-(void)checkActivityCount{
NSLog(#"test");
NSString *urlstring = #"https://exampleapp.com/api/v1/postactivity/?unreadfeedcount=yes";
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
BOOL success = [[JSON objectForKey:#"success"] boolValue];
if (success) {
if (![JSON[#"unread_activity_count"] isEqualToString:#"0"]) {
// Schedule the notification
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:2];
localNotification.alertBody = [NSString stringWithFormat:#"You have %# unread activities.",JSON[#"unread_activity_count"]];
localNotification.alertAction = #"Show me the item";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
// Request to reload table view data
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadData" object:self];
}
}
} failure:nil];
[operationQueue addOperation:operation];
[self performSelector:#selector(checkActivityCount) withObject:nil afterDelay:3000];
}
Now test1 gets logged, but test never logs. Am I doing something wrong in the code?

Using performSelector:withObject:afterDelay: pushes the request onto the queue for the thread. It doesn't wait for it. So immediately after you do that (even if something would pick the item from the queue in 3 seconds) you're telling the app that the background task is complete and the app gets shut down.
I haven't tried pausing like this, but try something more like:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self checkActivityCount];
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});

Related

local notification when not reachable and app in background

Goal is to notify end user about reachability changed when app is in background.
Broadcasting approach NSNotificationCenter not working in background.
second approach i tried beginBackgroundTaskWithExpirationHandler in applicationDidEnterBackground but associated issue with it:
a) Time limitation of 10 min
b) i calling a end loop for detecting the reachability state which run on main thread and in result it choke the UI. Code:-
-(void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"Application entered background state.");
// bgTask is a property of the class
if (isUserLogin) {
NSAssert(self.bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_current_queue(), ^{
[application endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_current_queue(), ^{
while ([application backgroundTimeRemaining] > 1.0) {
curReach = [[utilities sharedUtility]reachabilityChanged];
NetworkStatus netStatus = [curReach currentReachabilityStatus];
NSLog(#"-----------back ground task------------");
if (netStatus == ReachableViaWWAN || netStatus == ReachableViaWiFi) {
//isNetworkMessagePopup = YES;
}
else{
// if (isNetworkMessagePopup) {
// isNetworkMessagePopup = NO;
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif) {
localNotif.alertBody = FORMAT_UNABLE_TO_CONNECT_SERVER_DUE_TO_NO_INTERNET;
localNotif.alertAction = NSLocalizedString(#"Read Message", nil);
localNotif.soundName = #"pushNotification.caf";
localNotif.repeatInterval = 5;
//localNotif.applicationIconBadgeNumber = 1;
[application presentLocalNotificationNow:localNotif];
[localNotif release];
break;
//}
}
}
}
[application endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
});
}
}
Please suggest me is it possible to notify user in iOS whenever reachability changed and app in background state?
If yes then how can i achieve this.
Thanks.
You could possibly use the background fetch capability as described in the iOS App Programming Guide to check reach ability and post a local notification if the network is un available.
There is no guarantee of how often this will be called - probably in the order of every few minutes or longer - certainly not every few seconds.

I want to continue to process image and store it when iOS App in background

I tried to use NSOperation and NSOperationQueue.
But As getting into background, NSOperation didn't work. it stopped.
Calling
- (void)viewDidLoad
{
findFQueue = [[NSOperationQueue alloc] init];
FindFeatureOperation *testOperation = [[FindFeatureOperation alloc] init];
[findFQueue addOperation:testOperation];
}
NSOperation define
#import "FindFeatureOperation.h"
#implementation FindFeatureOperation
- (void)main
{
for (int i = 0; i < 999999 ; i++) {
NSLog(#"Operation %d", i);
[NSThread sleepForTimeInterval:1];
}
}
#end
Let me Know Please.
1 way: inside the op
to keep just running the operation:
- (main) {
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
for (int i = 0; i < 999999 ; i++) {
NSLog(#"Operation %d", i);
[NSThread sleepForTimeInterval:1];
}
[application endBackgroundTask];
}
2 way: using inside of applicationDidEnterBG:
- (void)applicationDidEnterBackground:(UIApplication *)app {
_bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// When Expired the limit time for background NSLog(#"Expired Background Task Limit Time");
[app endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[findFQueue waitUntilAllOperationsAreFinished];
[app endBackgroundTask];
});
}
Note: you can still be canceled if you use too much cpu / men / energy ... see the docs
Note 2: This can be written anywhere. I placed it in the OP but maybe in the VC is a better place... I don't think so but might be
Note 3: Read the docs! :: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html

how to call a method by using nstimer in background state

I want to fetch service for every 15 mins,so i am using NSTimer.It is working fine.But how to call same service while app is in background state by using nstimer.Nstimer is not working in background state.Please suggest me.
//when the application is about to move from active to inactive state.
- (void)applicationWillResignActive:(UIApplication *)application
{
[self sendBackgroundLocationToServer];
}
- (void) sendBackgroundLocationToServer
{
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
//Start Timer
[self startTimer];
//Close the task
if (bgTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}
}

call stopVideoCapture method in Background thread - iOS

i'm making video capture function with overlay view. And now i want to call stopVideoCapture method in UIApplicationDidEnterBackgroundNotification. but the "stopVideoCapture" method is always failed with error message “/var/mobile/Media/PhotoData/takingvideo activity indicator already cleared”.
please tell me what's the problem.
following is the code invoked in UIApplicationDidEnterBackgroundNotification
UIApplication *app = [UIApplication sharedApplication];
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (isRecording) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.imagePickerController stopVideoCapture];
});
}
[NSThread sleepForTimeInterval:5];
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
});

If the phone rings while playing in background mode

I'm making an iphone app(Live radio app).
My app is supported background mode.
But, if the phone rings when radio app is playing in background mode, my app stop with errors .
MP AVAudioSessionDelegateMediaPlayerOnly end interruption. Interruptor <Phone> category <completed> resumable <0>, _state = 6
MP endInterruptionFromInterruptor :: resuming playback
So, I modified my code, but useless.
I'll add my code. Please tell me my faults. Thanks.
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate, AVAudioSessionDelegate>
#property (assign, nonatomic) UIBackgroundTaskIdentifier bgTask;
... ...
#end
AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// 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;
});
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}
viewController.m
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
moviePlayer = [[MPMoviePlayerController alloc] init];
[moviePlayer setContentURL:... m3u8];
[moviePlayer play];
you need to add this:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

Resources