Transferring Data from Central to peripheral in Background mode in iOS - ios

I am developing an application for a custom wearable communicating through BLE.
I have subscribed to the UI background modes in the info.plist file for Bluetooth-central.
I am transferring a firmware file of around 600 kb by dividing into chunk sizes of 200 bytes each. The process is going fine but as I am pressing the Home button the app is entering into background state and thus terminating the process after 1-2 minutes.
If my screens dims after certain amount of time then the firmware transfer continues but as soon as the home button is pressed the app stops transferring the data after few minutes.
Please help me out of this scenario.
Thanks.

To run task in background mode, you need to follow the belowed steps.
Step 1: Declare __block UIBackgroundTaskIdentifier bgTask as global variable.
Step 2: To add following code in applicationDidEnterBackground.
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
bgTask = UIBackgroundTaskInvalid;
}];
}
Step 3: Stop background task handler once apps come in foreground mode.
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}

Related

continue fetching data from service in background

I am calling webservice in foregroud while the downloading is in progress, I press home button (app is in background now), I want to continue the fetching/downloading in background and complete it, is this possible in iOS? if yes then how can i achieve this?
Thanks in advance.
Please use URLSessionDownloadTask for downloading any data in the background and enable Background fetch under the background modes in capabilities.
For more info please refer,
Downloading files in background
Added below code in applicationDidEnterBackground appdelegate method and it works for me.
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];

app getting killed if using beginBackgroundTaskWithExpirationHandler IOS

I am using beginBackgroundTaskWithExpirationHandler method in the applicationDidEnterBackground delegate method for keeping the NSTimer to keep running. But then the application gets killed after a long time if left in background for a long time (in my case 7-10 mins). I don't want my app to be getting killed and also I want the timer to run if in background. How do I get rid of this issue. Following is the code that I have written in the applicationDidEnterBackground method
- (void)applicationDidEnterBackground:(UIApplication *)application {
if ([application respondsToSelector:#selector(setKeepAliveTimeout:handler:)]) {
[application setKeepAliveTimeout:600 handler:^{
DDLogVerbose(#"KeepAliveHandler");
// Do other keep alive stuff here.
}];
}
/*
* The following code is used to make the app running in background state as certain features
* (eg: NSTimer) doesn not run if its in background or if the phone is locked
*/
UIBackgroundTaskIdentifier locationUpdater =[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:locationUpdater];
} ];
}
The beginBackgroundTaskWithExpirationHandler is only intended to let you complete a finite length task of a few minutes after the app leaves foreground. iOS, quite deliberately, doesn't let your app run in background perpetually except for very narrow situations (e.g. VOIP, audio app, navigation app) or for narrow functional needs (significant change location services, background fetch, etc.). But you cannot just run arbitrary code perpetually in the background.
For a discussion of the options, see the Background Execution section of the App Programming Guide for iOS.

AVExportSession to run in background

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 most of times.
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.
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
But this does not seem to work. What am I doing wrong? Any help would be appreciated.
Sadly, since AVAssetExportSession uses the gpu to do some of it's work, it cannot run in the background if you are using an AVVideoComposition.

Know if GCD thread is running

In my iOS app I am download a fairly large amount of data in a background thread. What I need to do is somehow check when the user reopens the app if this task is still running or if it has been canceled.
If the user hits the home button for example, and then comes back to the app, the thread will continue which is good. But what if somehow the thread gets torn down by the OS. How can I on app resume know if a thread is running.
Thanks!
Some Code:
// Starts a background thread and also allows it to run in the background if the user exits app
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask:bgTask];
}];
// Code here to run in background
// Tell the main thread its done, and also remove itself from background execution
dispatch_async( dispatch_get_main_queue(), ^{
NSLog(#"Done with background thread");
[self endBackgroundUpdateTask:bgTask];
});
First off any thread, foreground or background will be suspended when your App goes into the background. There are some things you can do to get a small amount of time as you transition into the background to finish up and cleanup.... but your definitely getting shut down, "background" thread or not, when your app leaves the screen.
That means your download will have been suspended and you will have to gracefully recover and resume where you left off. For that you should investigate the techniques iOS offers for being notified your going into the background and being allowed some extra time to clean up and save some state that can be used to resume.
Investigate this:
beginBackgroundTaskWithExpirationHandler
Then use backgroundTimeRemaining to check how much time is left as you try to finish up in the extra time granted. When it's clear you can't finish in the allotted time save state and set a flag that indicates you need to continue or start over when the you re-launch. There is really no other way as iOS doesn't have any way of knowing if you finished what you were trying to do and it is up to you to

Preventing Screenshot/clearing cached data when iOS app gets backgrounded and resumed after a long time

I am building a cinema listing app, where the user can drill down thru the dataset to finally end up with a listing for a specific movie/theater/etc.
Now assume the user pauses using the app for 7 days. When reopening the app what he should not see are the listings from 7 days ago. But if the user just puts the app in background for a few minutes, the user should continue just where he left. I thought I could solve this issue by killing the app after a certain amount of time in background. This is the code:
static BOOL goingToQuit = NO;
#define KILL_IN_BACKGROUND_AFTER_SECS 300
- (void)applicationDidEnterBackground:(UIApplication *)application
{
goingToQuit = YES;
UIApplication* app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
if(UIBackgroundTaskInvalid != bgTask) {
// Start the long-running task to kill app after some secs and return immediately.
dispatch_after( dispatch_time(DISPATCH_TIME_NOW, KILL_IN_BACKGROUND_AFTER_SECS * 1e09),
dispatch_get_main_queue(), ^{
if(goingToQuit) exit(0);
[app endBackgroundTask: bgTask];
});
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// cancel ongoing background suicide.
goingToQuit = NO;
}
What I see on my device is this: after KILL_IN_BACKGROUND_AFTER_SECS the app gets killed. After restarting the device logs show that the app got a new PID, entries showing the restart etc. Yet the device does not show the default.png startup image, but the screenshot of where the user has been before.
On the other hand if the user kills the application explicitely (double click on home button, tap & hold, click - on app) before he is restarting it the application starts with its default.png start up screen. This is the behaviour I want when killing the app programmatically.
Does anyone have an idea how to accomplish this? Any idea is highly appreciated.
BTW: As a workaround I tried to hide the main window during applicationDidEnterBackground and show it again on applicationWillEnterForeground. This, however, is highly confusing to the user when he is switching between apps.
In your app delegate's applicationDidEnterBackground you can display a view in front of the rest of your views, which the OS will grab as the last visible thing and which will be displayed when the app becomes active again (if it's still alive).
In your app delegate's applicationDidBecomeActive you can check to see if the data needs updating; if not then simply dismiss the view (animation is nice), and if so then first update (or just clear out) your data and then dismiss the view.
This is fairly common in apps. Many just use the default.png startup image, since users are accustomed to seeing it when the app launches normally.

Resources