How does iOS keep the program running long in the background

  • 2020-12-10 00:53:30
  • OfStack

iOS uses tombstone-style "false background" for its background mechanism in order to save power, reduce unnecessary expenses and keep the system smooth. In addition to the system official few applications can be true background, 1 developers developed the application background is subject to the following restrictions:

1. After the user presses Home, App turns to the background to run. At this time, the background operation can be processed with the running time of 180s (iOS7) or 600s (iOS6)

2. After the time of 180S or 600S has passed, the system can be informed that the task has not been completed and the application needs to be completed. After the system approves the application, the system can continue to operate, but the total time will not exceed 10 minutes.

3. When the 10-minute time is up, no matter how you apply to the system to continue the background, the system will force the suspension of App and suspend all background operations and threads until the user clicks App again.

Of course, iOS also reserved 1 method to realize "true background" for special applications, and extracted the more commonly used methods:

1.VOIP

2. Location services

3. Background download

4. Live playing silent music in background 1 (it is easy to be affected by telephone or other programs, so it is not considered for now)

5... More.

VOIP needs to bind 1 Socket link and declare it to the system. The system will take over the connection in the background. Once the remote data comes, your App will be awakened for 10s (or less) time to process the data.

The background is now iOS7 introduced the new API, the implementation of the code is relatively small, bloggers did not carefully to find.

App, mainly done by The blog, needs to run directly in the background 1 and send messages to the server actively every 1 period to maintain the login status of the account, so it must ensure that App is not restricted by the tombstone of the system.

The blogger first tried many methods, including one Demo sent by a friend, destroying himself every 180s after the background time expired, and then creating another background task, but the actual test only lasted 10 minutes. Finally, considering that VOIP changes too much to the server side and the time is too tight, we choose the method of locating the service to keep the background.

To start the location service:

1. Need to introduce header file: #import

2. CLLocationManager * locationManager as defined in ES58en. m; As a global variable for easy control

3. Initialize the location service at the beginning of the program startup:


locationManager = [[CLLocationManager alloc] init];locationManager.delegate =self;
//or whatever class you have for managing location

The & # 8203; 4. When the program goes into the background, start the location service

[locationManager startUpdatingLocation]; (When running this method for the first time, if the user has not used App before, it will pop up whether the location service is allowed or not, and the following code will determine whether the user is allowed or not.)

In this way, when the positioning service is available, the program will constantly refresh the background time. In the actual test, it is found that the background time 180s is constantly refreshed, so as to achieve the purpose of long-term background.

However, there are also some problems with this use. On some machines, even if the location service is opened, it may not be able to refresh the background time, and the program needs to be completely finished before running. It is not known whether the stability is due to code or some mechanism of the system.

Paste the code below:

Note: The code contains demo given by my friend, and 180s is used to destroy the background method and then create my own background method. In the process of my implementation, I added positioning service to ensure that the background can be online directly.

Source reference part from the Internet, because read Google, found a lot of English blog, here thank the original author for sharing.

Determine whether the user has turned on the location service and disabled the program's location permissions:


if(![CLLocationManager locationServicesEnabled] || ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied))// Determine if the location service is on 
{
   [InterfaceFuncation ShowAlertWithMessage:@" error "AlertMessage:@" The location service is not open \n Staying online requires background location services \n Please go to   Settings - Privacy   Opens the location service "ButtonTitle:@" I was wrong "];
   return;
}

The & # 8203; AppDelegate. m source code:


@property(assign, nonatomic) UIBackgroundTaskIdentifier bgTask;
@property(strong, nonatomic) dispatch_block_t expirationHandler;
@property(assign, nonatomic)BOOL jobExpired;
@property(assign, nonatomic)BOOL background;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
  UIApplication* app = [UIApplication sharedApplication];
  __weak NSUAAAIOSAppDelegate* selfRef =self;
  self.expirationHandler = ^{ // Create background from wake up, when 180s At the end of the time the system will call this method 
    [app endBackgroundTask:selfRef.bgTask];
     selfRef.bgTask = UIBackgroundTaskInvalid;
     selfRef.bgTask = [app beginBackgroundTaskWithExpirationHandler:selfRef.expirationHandler];
     NSLog(@"Expired");
     selfRef.jobExpired =YES;
     while(selfRef.jobExpired)
     {
       // spin while we wait for the task to actually end.
       NSLog(@" Waiting for the 180s The end of the loop process ");
       [NSThreadsleepForTimeInterval:1];
     }
     // Restart the background task so we can run forever.
     [selfRef startBackgroundTask];
   };
   // Assume that we're in background at first since we get no notification from device that we're in background when
   // app launches immediately into background (i.e. when powering on the device or when the app is killed and restarted)
   [selfmonitorBatteryStateInBackground];
   locationManager = [[CLLocationManager alloc] init];
   locationManager.delegate =self;
   //[locationManager startUpdatingLocation];
   returnYES;
}
- (void)monitorBatteryStateInBackground
{
   self.background =YES;
   [selfstartBackgroundTask];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
   // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
   NSLog(@"App is active");
   [UIApplication sharedApplication].applicationIconBadgeNumber=0;// Cancel the application notification footer 
   [locationManager stopUpdatingLocation];
   self.background =NO;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
   // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
   // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
   //if([self bgTask])
   if(isLogined)// Background operation is not started until the login status 
   {
      self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:self.expirationHandler];
      NSLog(@"Entered background");
      [selfmonitorBatteryStateInBackground];
    }
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError*)error// This function is automatically called when an error occurs when the location service is unavailable 
{
   NSLog(@" Location service error ");
   if([error code]==kCLErrorDenied)// through error the code To determine the type of error 
   {
      //Access denied by user
      NSLog(@" The location service is not open ");
      [InterfaceFuncation ShowAlertWithMessage:@" error "AlertMessage:@" Location service not enabled \n The client needs to call the system's location service to hold the background function \n Please go to Settings to open location services "ButtonTitle:@" good "];
   }
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray*)locations// When the user's location changes, the system will automatically call, here must be written 1 Bit of code, otherwise background time refresh doesn't work 
{
    NSLog(@" Location change, something must be done to refresh the background time ");
    CLLocation *loc = [locations lastObject];
    //NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
    //NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);
    // Lat/Lon
    floatlatitudeMe = loc.coordinate.latitude;
    floatlongitudeMe = loc.coordinate.longitude;
}
- (void)startBackgroundTask
{
    NSLog(@"Restarting task");
    if(isLogined)// Only enter the background loop when logged in 
    {
      // Start the long-running task.
      NSLog(@" Login status background process on ");
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          // When the job expires it still keeps running since we never exited it. Thus have the expiration handler
          // set a flag that the job expired and use that to exit the while loop and end the task.
          NSIntegercount=0;
          BOOLNoticeNoBackground=false;// Only to inform 1 Time to sign a 
          BOOLFlushBackgroundTime=false;// Only to inform 1 Time to sign a 
          locationManager.distanceFilter = kCLDistanceFilterNone;// Any movement will be accepted and any movement will trigger the location update 
          locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;// Positioning accuracy 
          while(self.background && !self.jobExpired)
          {
              NSLog(@" Enter the background process loop ");
              [NSThreadsleepForTimeInterval:1];
              count++;
              if(count>60)// every 60s for 1 Second open positioning, refresh background time 
              {
                  count=0;
                  [locationManager startUpdatingLocation];
                  NSLog(@" Start location service ");
                  [NSThreadsleepForTimeInterval:1];
                  [locationManager stopUpdatingLocation];
                  NSLog(@" Stop location service ");
                  FlushBackgroundTime=false;
               }
               if(!isLogined)// Turn off the background when you are not logged in or are offline 
               {
                  NSLog(@" Keep the online process invalid and exit the background process ");
                  [InterfaceFuncation ShowLocalNotification:@" Remain online invalid, login has been logged out, please log in again "];
                  [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
                  return;// Exit the loop 
               }
               NSTimeIntervalbackgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
               NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);
               if(backgroundTimeRemaining<30&&NoticeNoBackground==false)
               {
                   [InterfaceFuncation ShowLocalNotification:@" Application to the system to keep the background for a long time failed, please end the client login again "];
                   NoticeNoBackground=true;
               }
               // Test the background time refresh 
               if(backgroundTimeRemaining>200&&FlushBackgroundTime==false)
               {
                  [[NSNotificationCenterdefaultCenter] postNotificationName:@"MessageUpdate"object:@" Background time refresh successfully \n"];
                  FlushBackgroundTime=true;
                  //[InterfaceFuncation ShowLocalNotification:@" Background time refresh successfully "];
                }
            }
            self.jobExpired =NO;
         });
     }
}


Related articles: