iOS后台行,一般有两种方式:
1.UIBackgroundTaskIdentifier后台任务标记时,
2.设置后台运行模式,需要有voip,location功能的才行。不然app上线审核肯定是过不了的。
下面是我学习后台运行的尝试过程。
一.首先创建一个项目功程用来测试后台运行情况。这里我参照别人的一篇文章,在后台增加角标值。
直接上代码。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//注册推送,设置角标也需要 不然角标显示不了
if(version >= 10.0)
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (error) { NSLog(@"request authorization error: %@", error); }
}];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}
//进入前台,结速后台任务
- (void) applicationWillEnterForeground:(UIApplication *)application
{
if(_badgeTimer)
{
dispatch_source_cancel(_badgeTimer);
_badgeTimer = nil;
}
}
//进入后台,开始后台任务,启动定时器每隔一秒给角标加一
- (void)applicationDidEnterBackground:(UIApplication *)application {
//方法一
[self stratBadgeNumberCount];
}
- (void)stratBadgeNumberCount{
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
if(_badgeTimer)
{
dispatch_source_cancel(_badgeTimer);
_badgeTimer = nil;
}
//定时器增加角标
_badgeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_badgeTimer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_badgeTimer, ^{
[UIApplication sharedApplication].applicationIconBadgeNumber++;
});
dispatch_resume(_badgeTimer);
}
程序运行后,返回后台。程序的角标加到1就不再增加了。 注意如果设置了后台运行模式
voip,locationt等会一直增加的。但是你app里没有这些功能的话app store审核肯定是过不了的。如下图
二.尝试使用UIBackgroundTaskIdentifier后台任务标记时
1) Background Task仅用于执行短时间的任务,APP切换到后台后,可以通过beginBackgroundTaskWithExpirationHandler申请一段时间的后台时间,你的任务应该在这段时间内执行完成,否则会被系统杀死。
2) Background Task的持续时间并不是一个固定值,在不同性能的设备上差别巨大。在iPhone 10上为30秒,这个是我自己测试的,据说,在高性能的设备上则达到180秒。最长持续时间似乎还和当前的资源占用情况有关。
3)beginBackgroundTask和endBackgroundTask必须成对出现如果使用全局的UIBackgroundTaskIdentifier记录后台任务,需要注意每次执行beginBackgroundTask都会生成新的UIBackgroundTaskIdentifier。旧的UIBackgroundTaskIdentifier会被覆盖,则上一个UIBackgroundTaskIdentifier就没有机会执行endBackgroundTask。此时会出现beginBackgroundTask和endBackgroundTask不配对的情况,可能会被系统杀死。
//进入后台,开始后台任务,启动定时器每隔一秒给角标加一
- (void)applicationDidEnterBackground:(UIApplication *)application {
//方法一
[self stratBadgeNumberCount];
[self startBgTask];
}
#pragma mark - 方法一
//开启后台任务
- (void)startBgTask{
UIApplication *application = [UIApplication sharedApplication];
if(_bgTask != UIBackgroundTaskInvalid)
{
[self endBackgroundTask];
}
_bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"%f",application.backgroundTimeRemaining);
//在这个地方重新开启后台任务不启作用
//[weakSelf startBgTask];
[self endBackgroundTask];
}];
}
//结束后台任务
- (void) endBackgroundTask
{
UIApplication *application = [UIApplication sharedApplication];
[application endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
}
使用UIBackgroundTaskIdentifier后台可以延迟30秒左右就被挂启了。测试结果是角标加到31就不再继续加了。据说以前ios可以延迟180秒。没测过。
三.Background Mode
启用Background Mode后(音频播放、后台定位、VoIP等),是没有后台时间限制的。
//进入前台,结速后台任务
- (void) applicationWillEnterForeground:(UIApplication *)application
{
// [self endBackgroundTask];
if(_badgeTimer)
{
dispatch_source_cancel(_badgeTimer);
_badgeTimer = nil;
}
}
//进入后台,开始后台任务,启动定时器每隔一秒给角标加一
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self stratBadgeNumberCount];
[self.player play];
//用AVAudioPlayer或CLLocationManager其一就可以
//方法三 (还没验证)
// self.appleLocationManager = [[CLLocationManager alloc] init];
// self.appleLocationManager.allowsBackgroundLocationUpdates = YES;
// self.appleLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
// self.appleLocationManager.delegate = self;
// [self.appleLocationManager requestAlwaysAuthorization];
// [self.appleLocationManager startUpdatingLocation];
}
- (void)stratBadgeNumberCount{
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
if(_badgeTimer)
{
dispatch_source_cancel(_badgeTimer);
_badgeTimer = nil;
}
//定时器增加角标
_badgeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_badgeTimer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_badgeTimer, ^{
[UIApplication sharedApplication].applicationIconBadgeNumber++;
});
dispatch_resume(_badgeTimer);
}
#pragma mark
- (AVAudioPlayer *)player{
if (!_player){
NSURL *url=[[NSBundle mainBundle]URLForResource:@"work5.mp3" withExtension:nil];
_player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
[_player prepareToPlay];
//一直循环播放
_player.numberOfLoops = -1;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
}
return _player;
}
#pragma mark
/** 苹果_用户位置更新后,会调用此函数 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
[self.appleLocationManager stopUpdatingLocation];
self.appleLocationManager.delegate = nil;
[UIApplication sharedApplication].applicationIconBadgeNumber++;
NSLog(@"success");
}
/** 苹果_定位失败后,会调用此函数 */
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
[self.appleLocationManager stopUpdatingLocation];
self.appleLocationManager.delegate = nil;
NSLog(@"error");
}
同时要加上后台运行的能力
参考:iOS 关于后台持续运行 - 简书