I am a new bee in iOS apps development. I want to create a background service in iOS. I also want to mention a particular time of the day and interval (every 2 hours) to call the service (kind of an Alarm to invoke service). When the service runs, some task should get performed independent of the state of app i.e. app can be in active or inactive state. Any example of it or a code snippet of implementation will help me implement this functionality.
Use this Code
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[Timer invalidate];
Timer = nil;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"Background process is Start(EnterBackground)!");
__block UIBackgroundTaskIdentifier bgTask ;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
Timer = [NSTimer scheduledTimerWithTimeInterval:120.0f target:self selector:#selector(process) userInfo:nil repeats:YES];
}
Related
I want to run a background task. for check the network connectivity even the application in background
-(void) beginBackgroundUploadTask
{
isBackGroundRunning = YES;
if(self.backgroundTask != UIBackgroundTaskInvalid)
{
[self endBackgroundUploadTask];
}
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background Time Remaining :%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
}];
}
-(void) endBackgroundUploadTask
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask ];
self. backgroundTask = UIBackgroundTaskInvalid;
}
-(void) initializeUpdateTimer
{
a= 0;
[self.updateTimer invalidate];
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(checkNetWorkStatus)
userInfo:nil repeats:YES];
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[[NSRunLoop currentRunLoop] addTimer:self.updateTimer forMode:NSDefaultRunLoopMode]; //NSDefaultRunLoopMode
[[NSRunLoop currentRunLoop] run];
});
}
}];
}
I am initializeUpdateTimer function when application comes to background.
The task is automatomatically stops after 3 minutes.
Is it possible to extend the time for 30 minutes.
Theres no way to check if Internet is available once your app is suspended, usually iOS suspends apps in 3 mins but it depends on the OS. But theres a hacky way
If you need to know that, is your app is awake or not try using silent push notification,
if you receive silent push set a local notification for 30 or more and if you receive another silent push notification remove local notification from its schedule,
if silent push never arrives let the local notification do its job.
its my way to implement your requirement but its never recommended, neither by me.
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 a app that fetch some content from server via REST api after every 5 mins in background using the UIBackgroundTaskIdentifier. My problem is that this works fine for 1,2 hours and then after it is expired it never re starts the background task. The code I am using is given below,
In AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIApplication* app = [UIApplication sharedApplication];
self.expirationHandler = ^{
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
// self.bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
NSLog(#"Expired");
self.jobExpired = YES;
while(self.jobExpired) {
// spin while we wait for the task to actually end.
[NSThread sleepForTimeInterval:1];
}
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Restart the background task so we can run forever.
[self startBackgroundTask];
};
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
[self monitorBatteryStateInBackground];
}
- (void)monitorBatteryStateInBackground
{
NSLog(#"Monitoring update");
self.background = YES;
[self startBackgroundTask];
}
- (void)startBackgroundTask
{
NSLog(#"Restarting task");
// Start the long-running task.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// When the job expires it still keeps running since we never exited it. Thus have the expiration handler
// set a flag that the job expired and use that to exit the while loop and end the task.
while(self.background && !self.jobExpired)
{
[self uploadPhotostoServer];
[NSThread sleepForTimeInterval:240.0];
}
self.jobExpired = NO;
});
}
In expired section it do come but never calls the method [self startBackgroundTask]
Any help will be much appreciated.
In my app , I am triggering many GET/POST request and handling the response. But just after initiating the request if I lock the device then on resuming the app after some seconds the response doesn`t come.Is there any way to let the request active even in the background or on the device locked state till the response comes. I went through the Background Execution Docs in iOS but that seems to be used if want to download or do something in background.Not fulfilling my scenario.
If you register a background task for each request, your app will keep running even when the device is locked, as long as a request is still active. The system only allows a maximum of 4 minutes though, so your requests mustn't take too long.
When you start a GET/POST request, do this:
__block UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
Then, store bgTask somewhere associated with your GET/POST request. Then when your request is complete, do this:
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
Wen app is closed applicationDidEnterBackground was called so put this background task code. put timer or cal the function what ever u want.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0),
^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
//// just u call the method want ever u want example
[self notification];
// (or) timer
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(notification:)
userInfo:nil
repeats:YES];
}
i think is help ful to u
I am using robbiehanson/CocoaAsyncSocket for async socket, when my iPad goes into background state i disconnect and close all the ports, but some times when iPad awakes from sleep it crashes, happened same with simulator when mac goes to sleep mode. Once i got crash log as [AsyncSocket close] unrecognized instance send to selector.
I am not able to find a solution for this, can any one help me on this. Below is my code for disconnecting.
- (void) enterBackground
{
if (self.discoveryUdpSocket!=nil)
{
self.discoveryUdpSocket.delegate = nil;
[self.discoveryUdpSocket close];
}
self.discoveryUdpSocket.delegate = nil;
self.discoveryUdpSocket = nil;
}
Have you tried to extend time when entering background mode to allow socket framework complete its job?
I mean to add in the app delegate a method:
-(void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Times up!");
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Let the async socket to complete its job and finally close the connection
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Finishing job and closing async socket, time remaining=%f", [app backgroundTimeRemaining]);
// Calling your background routine
[self enterBackground];
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
This is a good way to complete important job just before app is suspended. You have max 180 secs.