background

Typically, an iOS app is launched by the user by clicking on the icon, push, Widgets, etc. The app launch process is visible to the user, that is, the user can obviously perceive (see) the app launch. The application lifecycle in this case is familiar. In fact, applications can be launched “without the user’s awareness (or visibility),” which is referred to in this article as “background launch of applications.” Application background startup mechanism is provided by iOS system to developers to use a variety of API, is the principle of iOS application “survival”, careful study of “background startup mechanism”, can open a new dimension in many capabilities.

The life cycle

The startup process can be divided into “foreground startup” and “background startup” according to whether the application is started in the foreground. Foreground launch is a process in which users actively launch an application by clicking on an icon or by pushing or Widgets. Background startup is a process in which an application uses various system apis to enable the application to start in the background when certain events occur. The life cycles of the two processes are different.

The front desk to start the

As shown above,

  1. Application foreground startup, after the main function first, and then to UIApplication didFinishLaunchingWithOptions events, to the root view controller’s viewDidLoad, viewWillAppear, And then didBecomeActive, and then viewDidAppear.
  2. When the user is not using the application and pushes the application into the background, willResignActive and didEnterBackground events occur. Generally, application processes suspend after 3 minutes (if backgroundTask exists).
  3. When the user opens the application again (clicking on the icon, etc.), the willEnterForeground event and didBecomeActive event occur.

This is a very familiar start-up process.

The background to start

As shown in the figure above, when the application background starts, the user is unaware and the application is not in the foreground. So didBecomeActive is not going to fire.

  1. Application background starts, is still the first after the main function, and then to UIApplication didFinishLaunchingWithOptions events, To the root View Controller’s viewDidLoad, viewWillAppear, and viewDidAppear events. But the whole process is in the background, the user is not aware of.
  2. Notice, it’s not going to be didBecomeActive. (Literally, if the application is not in the foreground, it is not Active.)
  3. The application process enters the suspend state for a period of time. (This time is within our control, see below)
  4. When the user clicks the icon (or otherwise brings the application back to foreground), a willEnterForeground event occurs, followed by a didBecomeActive event.
  5. Once the application is back in the foreground, subsequent events are the same as “foreground boot”.

The life cycle of information when more application background, may refer to the document developer.apple.com/library/arc…

Background startup mode

Starting from iOS7, Apple introduced Background Fetch mechanism to enable the ability to launch apps from the Background. Later versions of iOS gradually added more mechanisms to enable apps to launch from the Background. Strictly speaking, if the background music playback ability, iOS6 can be started in the background, on the one hand is relatively long, and music playback application is a special application, developers will naturally notice the background to start the scene.

1, the Background to Fetch

Background Fetch is a data pull mechanism introduced in iOS7. It is mainly used for applications that require frequent updates, such as social, news, or weather apps. When this mechanism is implemented, the system will learn the user’s habit of using the application, and try to give the application a background start (or wake up) opportunity before the user opens the application next time, so that the application can prepare data in advance. For example, if the user always opens the app at 1pm, the system learns this habit and tries to trigger Background Fetch before 1pm.

This mechanism is simple to implement.

The first step is to check the Background fetch under Jailbreak -> Background Modes.

Make sure there are UIBackgroundModes in info.plist and fetch.

	<key>UIBackgroundModes</key>
	<array>
		<string>fetch</string>
	</array>
Copy the code

In the second step, the AppDelegate calls – [UIApplication setMinimumBackgroundFetchInterval:]

[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
Copy the code

Is NSTimeInterval setMinimumBackgroundFetchInterval parameter types, But apple suggest only need to fill in UIApplicationBackgroundFetchIntervalMinimum or UIApplicationBackgroundFetchIntervalNever, because the lowest call interval is recommended values, The final frequency of scheduling is system control. So if you want to enable Background the fetch, the incoming UIApplicationBackgroundFetchIntervalMinimum; If you want to disable, incoming UIApplicationBackgroundFetchIntervalNever.

The third step, realizes the AppDelegate application: performFetchWithCompletionHandler:.

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    completionHandler(UIBackgroundFetchResultNewData);
//    completionHandler(UIBackgroundFetchResultNoData);
//    completionHandler(UIBackgroundFetchResultFailed);
}
Copy the code

After entering this callback, we can tell the system via the completionHandler that “background data fetching is ready and the system can suspend the process.” When completionHandler is called, the system immediately suspends the process.

There are three UIBackgroundFetchResultNewData completionHandler parameters, NoData, and Failed, the three results after tests found no significant differences at present, may be used to link a user behavior study parameters.

When the application starts (or wakes up) in the background, the completionHandler must be called within 30 seconds or the system will kill the process. The completionHandler controls the background lifetime of the process.

2, Remote Notifications

When the Apple Push Notification Service (APNs) is used, if the pushed field contains content-available in the code below, the system tries to start or wake up the application from the background.

{
   "aps" : {
      "content-available" : 1
   },
   "demo1" : "bar",
   "demo2" : 42
}
Copy the code

As with Background Fetch, it also needs to check Remote Notifications under Background Modes.

The implementation is the standard APNs configuration, and methods can be implemented at the AppDelegate level:

//iOS >=7 && <=9
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{   
}
// iOS >=10
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
}
Copy the code

The method application: didReceiveRemoteNotification: fetchCompletionHandler: there is a similar methods: application: didReceiveRemoteNotification: , the difference is: application: didReceiveRemoteNotification: fetchCompletionHandler will call in at the front desk, not just the background will be, too. When the system receives this push, it also tries to start or wake up the application in the background. More important, of course, is the parameter completionHandler, which controls how long the process lives in the background.

Detailed refer to apple document developer.apple.com/documentati…

Significant Location Update 3

When the request location permissions, you can request permissions of “background” when locating authority have the background, the application can invoke the CLLocationManager startMonitoringSignificantLocationChanges method enable “listening” significant position change, When there is a significant change in GPS position (the actual test is usually 4 to 500 meters), the application will start in the background.

First, you need CLLocationManager to request background location permission (Always),

-[CLLocationManager requestAlwaysAuthorization]
Copy the code

When there’s a Always in the permissions, the application startup can invoke startMonitoringSignificantLocationChanges to start listening to the location has changed significantly.

-[CLLocationManager startMonitoringSignificantLocationChanges]
Copy the code

When called, the next time geolocation sends a significant change, the application is launched from the background and the following method is called:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
}
Copy the code

Detailed reference document developer.apple.com/documentati…

4, HealthKit

When applications have access to health data, such as steps, can use HKHealthStore enableBackgroundDeliveryForType: frequency: withCompletion methods, the use of the background to monitor health data. At present, most Internet applications such as wechat and Alipay acquire the number of steps, and these applications can realize background startup by monitoring the change of steps. Of course, for the sake of the user’s battery power, Apple will limit the background wake-up frequency of some data, for example, the number of steps is at most once an hour.

For example, we want to read the user’s steps and listen for changes.

The first step is to request permission on the number of steps.

store_ = [[HKHealthStore alloc]init]; HKObjectType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; HKAuthorizationStatus status = [store_ authorizationStatusForType:stepType]; switch (status) { case HKAuthorizationStatusNotDetermined:{ NSSet<HKSampleType*> *readTypes = [NSSet setWithArray:@[stepType]]; [store_ requestAuthorizationToShareTypes:nil readTypes:readTypes completion:^(BOOL success, NSError * _Nullable error) { //... }]; break; } case HKAuthorizationStatusSharingDenied: case HKAuthorizationStatusSharingAuthorized: //... }}Copy the code

Second, listen for changes in the number of steps.

 [store_ enableBackgroundDeliveryForType:stepType frequency:HKUpdateFrequencyHourly withCompletion:^(BOOL success, NSError * _Nullable error) {
        if(success){
        }
    }];
Copy the code

The third step is to execute HKObserverQuery in response to notification of the change in the number of steps.

    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:nowDay endDate:nextDay options:(HKQueryOptionNone)];
    HKObserverQuery *query = [[HKObserverQuery alloc] initWithSampleType:stepType predicate:predicate updateHandler:^(HKObserverQuery * _Nonnull query, HKObserverQueryCompletionHandler  _Nonnull completionHandler, NSError * _Nullable error) {
        // completionHandler
    }];
    [store_ executeQuery:query];
Copy the code

Detailed documentation can be reference developer.apple.com/documentati…

4, other

In addition to the above mentioned methods, there are several other methods that can trigger background startup, such as Bluetooth, music, VOIP, Network Extensions, etc., which have different application scenarios. The diagram below:

Same and different

Different apis can bring about background startup, with some similarities and a few differences.

  1. There is a completionHandler for all the corresponding callback methods that start in the background. In order to ensure that it does not consume too much power, the system will give the application a maximum Background survival time, for example, Background fetch is at most 30 seconds, and other methods are at most 1 minute. If the application does not call completionHandler by itself over the time, the system will directly kill the process.
  2. Both Background Fetch and Remote Notifications can be turned off by setting – General – Background App Refresh.
  3. Significant Location Update and HKHealthKit both require permission from the user.
  4. Background Fetch and Remote Notifications are useless when the user actively kills the process, only when the application is pushed into the Background and recycled by the system. Apple developers may see this as a case of users abandoning the automatic refresh feature of their apps.

Start a new dimension of optimization

Application launch speed is a metric that every large application must pay special attention to, and the discovery of “background launch” gives us a new dimension of optimization.

We are concerned about the startup time of an app, which is “the time that the user feels from clicking on the icon to being displayed on the home page”. So what is the difference between “foreground launch” and “background launch”?

The front desk to start the

The following figure shows the startup time of the foreground from the user perspective and the application perspective, indicating that the two are equivalent.

Assuming that the dots below are all that you need to do to start, the foreground start process is “do it all from the beginning.”

The background to start

The following figure compares the background startup time between users and applications. It can be seen that during background startup, the application has extra time to execute the code, which can be used to complete the application startup task in advance. When the user clicks on the icon, only a small amount of code needs to be executed.

When there is background startup, most of the startup tasks can be completed in the background. For example, the gray dots in the figure below are background tasks and the green dots are foreground tasks. When the user clicks the icon back to the foreground, only a small number of startup tasks can be performed.

Matters needing attention

“Background startup” opens another way for application startup, which has a great impact on the application. Note the following:

  1. IOS processes are in the running, suspend, and Killed states. In particular, the suspend state is common in iOS. Background Startup Mechanisms Suspend and resume processes frequently while making them start in the background. Because suspend is more likely, our code needs to adapt to this environment. For example, if the process suspend occurs between the start and end times, the difference can be large. In addition, sockets in long connections may increase the probability of false connections on the server because of SUSPEND.

  2. For each Background startup mechanism, there is a corresponding concept of “maximum Background lifetime of a process”, for example, Background Fetch is 30 seconds. At the same time, we should also be responsible for the power of the user’s phone and control the power.

  3. The more background startup mechanisms you implement, the more frequently your application will start in the background,

    1. If the user actually opened the application once for each of the five background launches, the number of network requests during the original startup phase would be five times as high.
    2. In addition, the background startup process is not aware of users, network requests will generate traffic.
    3. Therefore, from the perspective of server pressure and user traffic consumption, network requests started in the background need to be limited.
  4. The business logic aspects of the code, such as how DAU is calculated or how page PV/UV is calculated, also need to be evaluated for correctness based on the lifecycle.

  5. There will be a “background flash back”, or “sensorless flash back”. For example, when the user does not open the application, the application flashes back after background startup, which is a kind of “unconscious flash back” to the user.

  6. For App Store approval, most backend startup capabilities are supported by business scenarios. Background Fetch and Remote Notifications do not require special associated business scenarios, HealthKit needs to obtain the number of steps, and Significant Location Update requires Background positioning, such as overseas business scenarios.

conclusion

Background startup of applications gives applications a new way to start, giving them more time to execute, just like a new means of transportation for human beings to go out, bringing new capabilities and risks at the same time, but as long as careful evaluation and appropriate use, can enable our applications to do something that could not be done before.

Background start self-test

Although we know the background startup function, because it is controlled by iOS system, we need to test the background startup in a special way:

Methods a

Edit Scheme —-> Option —-> Background Fatch, check

And then run, you start in the background.

Way 2

Run the application directly. From the Menu of Xcode, select “Debug” -> “Simulate Background Fetch”. Void Application: PerformFetchWithCompletionHandler method.