iOS solves the problem of application backstage timer and location update stopping

Keywords: iOS Attribute SDK

Because iOS system is a "pseudo background" mode of operation, when the HOME key is pressed, if the program does not do any operation, the application will have 5 seconds of execution buffer time, the random program will be suspended, all task terminals, including timers and location updates, etc., but when the program opens the background mode switch, some tasks can be performed in the background, such as audio, location, Bluetooth, download, VOIP. Even so, the program can run in the background for up to 594 seconds (about 10 minutes). Unfortunately, a program that declares background mode is likely to be rejected when the app is on the shelf. Based on this, I have developed a way to keep the timer and location running when the app enters the foreground without declaring the background mode.

The realization principle is as follows:

Using iOS notification mechanism, when the program enters the background and returns to the foreground again, it sends notifications, records the current time of entering the background and the current time of returning to the foreground again, calculates the time interval between the two, adds notification listeners anywhere the program needs, and executes code blocks in the listening method. The parameters in the code blocks are the notification object and the calculated time interval. Take the timer as an example, when the program enters the background, the timer stops running. At this time, using the above method, the content of the code block is executed when the program returns to the foreground again. The current time interval of the timer when the program enters the background together with the time interval parameter of the code block can make the timer timing accurately and accurately. No more nonsense, code it:

In the AppDelegate.m implementation file:

- (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.
    [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil];
}


- (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.
    [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotification object:nil];
}

Code description: After the program enters the background, the system notification mechanism is used to notify the program to enter the background and return to the foreground again. The object of monitoring is all the objects.

Then define a class YTHandlerEnterBackground that handlers go into the background

//
//  YTHandlerEnterBackground.h
//  Time sharing lease
//
//  Created by Cox spectrum on 17/2/24.
//  Copyright © 2017 Nian Keqipu. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

/** Enter Backstage Block Typeedef */
typedef void(^YTHandlerEnterBackgroundBlock)(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime);

/** Processing goes into the background and calculates the class of time intervals left behind */
@interface YTHandlerEnterBackground : NSObject

/** Add observers and process the background */
+ (void)addObserverUsingBlock:(nullable YTHandlerEnterBackgroundBlock)block;
/** Remove background observers */
+ (void)removeNotificationObserver:(nullable id)observer;

@end

In the YTHandler EnterBackground.m implementation file:

 

//
//  YTHandlerEnterBackground.m
//  Time sharing lease
//
//  Created by Cox spectrum on 17/2/24.
//  Copyright © 2017 Nian Keqipu. All rights reserved.
//

#import "YTHandlerEnterBackground.h"

@implementation YTHandlerEnterBackground

+ (void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block {
    __block CFAbsoluteTime enterBackgroundTime;
    [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        if (![note.object isKindOfClass:[UIApplication class]]) {
            enterBackgroundTime = CFAbsoluteTimeGetCurrent();
        }
    }];
    __block CFAbsoluteTime enterForegroundTime;
    [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        if (![note.object isKindOfClass:[UIApplication class]]) {
            enterForegroundTime = CFAbsoluteTimeGetCurrent();
            CFAbsoluteTime timeInterval = enterForegroundTime-enterBackgroundTime;
            block? block(note, timeInterval): nil;
        }
    }];
}

+ (void)removeNotificationObserver:(id)observer {
    if (!observer) {
        return;
    }
    [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationWillEnterForegroundNotification object:nil];
}

@end

 

This class implements a method to add and process the background and remove the notification listener. It should be noted that in the addObserver UsingBlock method, there must be an if (![note.object is KindOfClass:[UIApplication class]) judgment, otherwise the code block in the addObserver ForName method will execute many times, and this code is executed twice. The addObserver UsingBlock method calls the add notification listener in the viewWillAppear method and the remove notification listener in the viewWillDisappear method.

 

For example, in a timer NSTimer controller:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
        self.rentTimerInterval = self.rentTimerInterval-stayBackgroundTime;
    }];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.timer invalidate];
    [YTHandlerEnterBackground removeNotificationObserver:self];
}

I defined a timer attribute for a countdown 5 minutes object and a rentTimerInterval attribute for the current countdown interval of the timer. In the add-in notification listener code block, rentTimerInterval equals the countdown interval when entering the background minus the time interval when the program stays in the background. When the timer returns to the foreground again, the time of the timer at this time The interval is continuous. Although the timer does not run continuously in the background, this method is also used to achieve the correct real-time timer.

 

Similarly, when the program has the function of location updating, when the program enters the background, the location service object will automatically stop updating. At this time, the method of invoking the above two processes into the background still makes the program enter the background and start positioning again:

In classes requiring location updates:

 

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.locService.delegate = self;
    [self.locService startUserLocationService];
    //Enter the background and enter the foreground to relocate
    [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
        [self.locService startUserLocationService];
    }];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    //Stop location
    self.locService.delegate = nil;
    [self.locService stopUserLocationService];
    //Remove background monitoring
    [YTHandlerEnterBackground removeNotificationObserver:self];
}

Baidu Map SDK is used here.

 

Using this method, tasks that need to run in the background, such as timers and location updates, can meet the corresponding requirements, but the trouble is that these two methods should be invoked in any class that needs them. You can add other parameters when the program enters the background and returns to the foreground according to your needs (notification object parameters are necessary), such as after saving the entry. Operations in front of the desk and so on. Or define different ways to add notification listeners to meet different needs.

Posted by gva482 on Fri, 12 Apr 2019 11:03:31 -0700