Implement updating location to server in the background mode- iOS - ios

What I want do is:
Updating the current location of iOS device to my server periodically(every 10min), even my App is in the background mode.
What I have done:
Add the Required Background Modes in the plist; and asked requestAlwaysAuthorization.
Set background refreshing of this App in Setting.
Set a NSTimer to get the location(using CLLocationManager) periodically.
When the locationManager: didUpdateLocations:delegate called, updating location use HTTPGET to the server.
My problem:
When App is in foreground it works fine, but the update location method does not run in background, server cannot receive my location data.
Thank you.

Please check if you have enable Location in background modes from project settings -> Target -> Capabilities.
Instead of location send to server in every 10 mins , I would like to suggest you use startMonitoringVisits() and locationManager(_:didVisit:) delegate to get user location. Because your approach will be too much battery killer.

You have to register your background task with below code and then your task is finish you have to end background 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.
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;
});
}
for more info: apple document

Related

Apple's background execution example for ios

Apple gives this of background execution:
- (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.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
This example has never made much sense to me and I've seen it copied to numerous background application examples.
The first thing that doesn't make sense are these two lines in the expirationHandler:
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
It seems like bgTask won't have a value when captured in the block. The compiler complains as such. Then below in the dispatch_async the sample shows the same two lines. I would expect it in the dispatch_async but not in the block. Can anyone explain why we have these lines in the block?
Also the documentation per beginBackgroundTaskWithName says "Marks the beginning of a new long-running background task." How exactly is it doing this? What defines the task? Is it any code that follows in the block scope?
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:]
tells iOS that your application is starting a new background task. iOS doesn't care which code comprises the task, it just knows that it needs to give your app more time to execute in the background.
After this line executes, bgTask will contain the new background task identifier.
When your background task is complete, you then call [application endBackgroundTask:bgTask]; and iOS knows that your app has finished the specified background task and may not need any more background execution time (You may still have other background tasks initiated by beginBackgroundTaskWithName:expirationHandler outstanding).
The line:
bgTask = UIBackgroundTaskInvalid;
is just housekeeping; If you omit this line nothing bad will happen, but bgTask will contain an invalid identifier.
If you don't call endBackgroundTask before your app's background time expires, then then expiration handler block will be invoked.
In the expiration handler bgTask will have the value that was assigned when you called beginBackgroundTaskWithName:expirationHandler, so this is what is passed to endBackgroundTask and again assigning UIBackgroundTaskInvalid is just housekeeping

BLE background operation issue

I am trying to transfer a firmware file from my app to a wearable hardware.
it takes about some time and when my app goes in background or the lock button is pressed the firmware transfer process discontinues.
ideally it should continue to transfer the firmware. I am using this method to continue the process in background and also also have declared the support for the background modes.
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = 0;
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;
});
}
This method is not able to do the task.
However if I use this method in Appdelegate - didFinishLaunchingWithOptions it works.
But there is a trade off with putting this piece of code in the above method i.e If I am not transferring the firmware and the app goes in background then after 3 mins this piece of code removes the app and bluetooth connection breaks.
If I am not using this method at all, then the connection remains until it is broken manually but background transfer does not happen.
I have to keep both the operations simultaneously. Please suggest something as I have been for many days on this particular problem.
Thanks in advance.
Try to run your application using BackgroundModes
and remove all the codes from didEnterInbackground

Perform NSLog when App is Sent to Background

I have a seemingly simple task that I am trying to do. When a user sends my application to the background, I would like to conduct an NSLog to say "app sent to background". I am trying to work with the NSNotificationCenter like What's the best way to detect when the app is entering the background for my view?, but I am unable to get it to work.
Is it not possible to perform an action right when the user sends the app to the background? Any help would be great!
Thanks!
You may use NSLog in method of
- (void)applicationDidEnterBackground:(UIApplication *)application
Your AppDelegate.m file.
Where you can send NSNotification for any task. You can not perform any task when app is in background.
You need to implement the following method in AppDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"app sent to background");
}
Apple's documentation:
Your implementation of this method has approximately five seconds to
perform any tasks and return. If you need additional time to perform
any final tasks, you can request additional execution time from the
system by calling beginBackgroundTaskWithExpirationHandler:.
You can do a 10 min background activity in pre iOS7 like save some thing to your server but in order to wind up when background activity is about to be closed you need to use this in your - (void)applicationDidEnterBackground:(UIApplication *)application
- (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;
});
}
For more detail look here
the summary is
your - (void)applicationDidEnterBackground:(UIApplication *)application method must return within 5 seconds or else your app will be purged.
you can how ever ask for more time using the above method the time allowed in practice is 10 mins

Continue operation when app did enter background on iOS

in my app i have some NSOperation that update some core data element from a online database, sometime the update require some minute, and when the screen of iPhone lock, the app enter in the background mode, and this update is stopped, so i have to reopen the app to continue the update, so i have search a lot on stack overflow and i have find some information about:
beginBackgroundTaskWithExpirationHandler
that is a method from apple that let continue some task also when the app is in the background mode, and i have do this:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}
and now the app continue the task in the background, and seems that all works fine, so my question is, this method i use is safe? or there is a better mode?
thanks
That's not how you do this. Any code that you want to run in the background must be wrapped properly. Something like this:
- (void)someMethodToKeepRunningInBackground {
UIBackgroundTaskIdentifier taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
// Uh-oh - we took too long. Stop task.
}];
// Perform task here
if (taskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:taskId];
}
}
You don't do anything in the UIApplicationDelegate applicationDidEnterBackground: method.
Any task that is wrapped inside the "background task" calls will be allowed to keep running when the app enters the background.
Here's the really important part - the task only gets 10 minutes maximum. If it is still running after 10 minutes your app will be terminated. The expiration handler gives you a few seconds to cleanly end the task before the app is terminated uncleanly.

Multiple beginBackgroundTaskWithExpirationHandler

If we have a long running task, we can ensure that the application doesn't quit until that task is complete by using the following piece of code:
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Do the work associated with the task, preferably in chunks.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
In my case, the applications plist contains an entry for Application does not run in background set to YES. Now, i have a serial queue (dispatch_queue_create(..., NULL)) that logs the operations and perform them one by one. User can post many tasks at a time and it might take couple of seconds 20-30 for all of them to complete.
Now my question is, can i use beginBackgroundTaskWithExpirationHandler with my serial queue? If so, any recommendations as to how? I believe i'll have to maintain an array of UIBackgroundTaskIdentifier?
To the best of my knowledge, if the application doesn't support background processing, the application quits immediately. So, starting a background tasks is not possible.

Resources