Background data update in iOS7
At the end of September, APPLE released iOS 7, one of the features of this version was improved multitasking and the ability to update data when the application is not active.
There are two options for launching an application for updating data - periodic updates and launching when a special push notification is received. In each of the options, the application will be launched in the background mode and will be forced to close after 30 seconds, so there will be very little time for updating.
To allow the application to run in the background, add the Required background modes key with the value App downloads content from the network to the application plist. This can also be done by checking the Capabilities tab.
In addition, you need to set the minimum interval for launch in the application: didFinishLaunchingWithOptions: method.
(version checking is important - in iOS 6 the application crashes on this function).
Instead of a numerical value, you can use the UIApplicationBackgroundFetchIntervalMinimum variable to set the minimum possible interval, but this does not play a special role, because the minimum, and not guaranteed, interval is set. When exactly the application will start is unknown. It will be launched on the basis of performance statistics: at what time the application usually starts, how much time is usually in the background. The less time it takes for the program to work, the more often it will start. Setting the interval is required, because by default, this value is equal to UIApplicationBackgroundFetchIntervalNever and will not start.
When launched, the application starts its work in the background by running the application: performFetchWithCompletionHandler method:
At the end of the method, you must call the resulting completionHandler with the UIBackgroundFetchResultNewData parameter (options - UIBackgroundFetchResultNoData, UIBackgroundFetchResultFailed). But in any case, after 30 seconds the application will be forced to close.
In addition, as with standard startup, application: didFinishLaunchingWithOptions: is called
and if it contains code that should not be run in this situation (for example, updating the UI), it is better to disable it in order to save processor time. When starting in this mode, I did not find additional keys in launchOptions, so I need to check the application.applicationState parameter, which will be equal to UIApplicationStateBackground.
NB If within 30 seconds while the application is running in the background, the user starts the application through the UI, then this method will not be restarted. If necessary, you can run the missing code in the applicationWillEnterForeground: (UIApplication *) application method.
To debug the application launch in the background update mode, Xcode can simulate this mode - it is enabled by a tick in the scheme settings.
The second way to get a content update is to start when you receive a push notification with the content-available flag set.
I will not schedule the application settings for receiving push. I can only say that the Required background modes key with the value App downloads content in response to push notifications (well, or the corresponding checkmark in the project settings) is added to the
application plist, and the new value UIRemoteNotificationTypeNewsstandContentAvailability is added to the types of messages that the application will receive ;
When a message is received, the method starts
which
will also be given only 30 seconds and at the end of which it is necessary to call completionHandler with a parameter.
This function will be launched regardless of the current state of the application, even if it is in active mode.
If the application starts in the background, the application: didFinishLaunchingWithOptions: method will also be called, but in this case there will be an entry in the launchOptions with the key UIApplicationLaunchOptionsRemoteNotificationKey.
The first pitfall - push does not come if there is nothing besides the content-available flag. If you add text or sound, then everything is fine. Since no one wants to spam the user with messages, we send an empty sound:
In principle, Apple does not limit us in choosing the method by which the update will be carried out. However, iOS 7 introduced a new NSURLSession class, which the company recommends using. Without delving into his description, one can say that one of its advantages is the ability to download data in the background using iOS itself, even after the application terminates.
And now, a little personal experience or why for our application (electronic newspaper on the iPad) all of the above did not work. It was planned that in the morning the user would wake up, take out the iPad, and the newspaper was already ready for him and was waiting to be read. But ...
Firstly, the background update does not work when the device is in sleep mode (the screen is off). The update will take place as soon as the screen is unlocked, this is good for the messenger, but for us it is too late.
Secondly, despite the fact that the documentation says “If your app is suspended or not running, the system wakes up or launches your app and puts it into the background running state before calling the method.”, Push does not start the application, if it is in the “not running” state. This means that if the user himself deleted the application from the task list or the system unloaded it, then push arrives, but the application does not start. It is not clear whether this is a bug or not, but what is, that is. Alas.
PS In order for the application to start, you must also enable the ability to start in the device settings (or rather, do not prohibit, because by default it is enabled for new programs). You can verify this from the application by monitoring the [[UIApplication sharedApplication] backgroundRefreshStatus] value.
There are two options for launching an application for updating data - periodic updates and launching when a special push notification is received. In each of the options, the application will be launched in the background mode and will be forced to close after 30 seconds, so there will be very little time for updating.
Periodic data refresh (Background fetch)
To allow the application to run in the background, add the Required background modes key with the value App downloads content from the network to the application plist. This can also be done by checking the Capabilities tab.
In addition, you need to set the minimum interval for launch in the application: didFinishLaunchingWithOptions: method.
If([[[UIDevice currentDevice] systemVersion] floatValue] >=7.0){
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:600];
}
(version checking is important - in iOS 6 the application crashes on this function).
Instead of a numerical value, you can use the UIApplicationBackgroundFetchIntervalMinimum variable to set the minimum possible interval, but this does not play a special role, because the minimum, and not guaranteed, interval is set. When exactly the application will start is unknown. It will be launched on the basis of performance statistics: at what time the application usually starts, how much time is usually in the background. The less time it takes for the program to work, the more often it will start. Setting the interval is required, because by default, this value is equal to UIApplicationBackgroundFetchIntervalNever and will not start.
When launched, the application starts its work in the background by running the application: performFetchWithCompletionHandler method:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
//DO SOMETHING
completionHandler(UIBackgroundFetchResultNewData);
}
At the end of the method, you must call the resulting completionHandler with the UIBackgroundFetchResultNewData parameter (options - UIBackgroundFetchResultNoData, UIBackgroundFetchResultFailed). But in any case, after 30 seconds the application will be forced to close.
In addition, as with standard startup, application: didFinishLaunchingWithOptions: is called
and if it contains code that should not be run in this situation (for example, updating the UI), it is better to disable it in order to save processor time. When starting in this mode, I did not find additional keys in launchOptions, so I need to check the application.applicationState parameter, which will be equal to UIApplicationStateBackground.
NB If within 30 seconds while the application is running in the background, the user starts the application through the UI, then this method will not be restarted. If necessary, you can run the missing code in the applicationWillEnterForeground: (UIApplication *) application method.
To debug the application launch in the background update mode, Xcode can simulate this mode - it is enabled by a tick in the scheme settings.
Running from a push message.
The second way to get a content update is to start when you receive a push notification with the content-available flag set.
I will not schedule the application settings for receiving push. I can only say that the Required background modes key with the value App downloads content in response to push notifications (well, or the corresponding checkmark in the project settings) is added to the
application plist, and the new value UIRemoteNotificationTypeNewsstandContentAvailability is added to the types of messages that the application will receive ;
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeNewsstandContentAvailability;
[application registerForRemoteNotificationTypes:myTypes];
When a message is received, the method starts
-(void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
//DO SOMETHING
completionHandler(UIBackgroundFetchResultNewData);
}
which
will also be given only 30 seconds and at the end of which it is necessary to call completionHandler with a parameter.
This function will be launched regardless of the current state of the application, even if it is in active mode.
If the application starts in the background, the application: didFinishLaunchingWithOptions: method will also be called, but in this case there will be an entry in the launchOptions with the key UIApplicationLaunchOptionsRemoteNotificationKey.
The first pitfall - push does not come if there is nothing besides the content-available flag. If you add text or sound, then everything is fine. Since no one wants to spam the user with messages, we send an empty sound:
aps = {
"content-available" = 1;
sound = "";
};
What can be done in 30 seconds?
In principle, Apple does not limit us in choosing the method by which the update will be carried out. However, iOS 7 introduced a new NSURLSession class, which the company recommends using. Without delving into his description, one can say that one of its advantages is the ability to download data in the background using iOS itself, even after the application terminates.
A spoon of tar
And now, a little personal experience or why for our application (electronic newspaper on the iPad) all of the above did not work. It was planned that in the morning the user would wake up, take out the iPad, and the newspaper was already ready for him and was waiting to be read. But ...
Firstly, the background update does not work when the device is in sleep mode (the screen is off). The update will take place as soon as the screen is unlocked, this is good for the messenger, but for us it is too late.
Secondly, despite the fact that the documentation says “If your app is suspended or not running, the system wakes up or launches your app and puts it into the background running state before calling the method.”, Push does not start the application, if it is in the “not running” state. This means that if the user himself deleted the application from the task list or the system unloaded it, then push arrives, but the application does not start. It is not clear whether this is a bug or not, but what is, that is. Alas.
PS In order for the application to start, you must also enable the ability to start in the device settings (or rather, do not prohibit, because by default it is enabled for new programs). You can verify this from the application by monitoring the [[UIApplication sharedApplication] backgroundRefreshStatus] value.