BLE background operation issue - ios

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

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

backgroundTask not finishing in iOS

I have the following code which makes a call to the server, before the app is about to exit. My problem is, that the code sometimes works, sometimes not. Mostly not. Here is the code:
//Set the user as in-active if app is force closed
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(#"called");
bgTask = [application beginBackgroundTaskWithName:#"setInActive" expirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"disp called");
//If the app is about to exit make the user inactive
[[APIManager sharedInstance] setInActiveOnCompletion:^(BOOL finished){
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
});
}
The first NSLog gets called everytime. However the second one does not. It seems as if the app does not even go into the dispatch_async method.
EDIT: So basically all I need to do is tell the server that a user has force quit the app, while that user was signed in. How could I do this?
Any ideas?
applicationWillTerminate is the last method that get called before app is being terminated!! So, you can't do anything after that, if you want to perform something in background then begin that task when you performing your operation, you can't begin background task from applicationWillTerminate because your app will not be in background after this method call!!
When your application is in the background, it is only allowed very little amount of processing, therefore using dispatch_async will not buy you much extra time. Also, Apple does not want that.

Implement updating location to server in the background mode- 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

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