Ios后台任务运行实现

时间:2022-11-18 23:49:06

Ios系统是个伪后台,它不能像android那样常驻后台来运行自己的程序,这就给一些希望常驻的程序带来的困扰。当然,ios也提供了几种方式让你可以以某种方式常驻后台,这几种方式是苹果固定死的,它们有voip, music, location等,如果你的app标注为以上类型的话,ios是允许你的APP常驻后台的(但是这里不得不说,如果你标注了以上几种类型,但是你的APP却和标注的类型没有关系,AppStore是拒绝你上架的,企业发布除外),那么问题就来了,如何实现一个常驻后台的APP呢?下面我将用实际代码来演示如何编写一个常驻后台的APP。

        第一步,你需要标注你的APP为voip, music,和location等类型的一种或者多种,具体方法是在plist文件中,添加一个名为"Required background modes"的键,并在此键下添加标注类型。

        第二步,就可以再AppDelegate.m中的applicationDidEnterBackground:(UIApplication*)application这个委托函数中实现后台运行代码了。

        首先你应该定义如下两个变量:

     UIBackgroundTaskIdentifier m_taskId;  // 后台任务id
BOOL m_bRun; // 是否有后台任务运行的标志
       其次,你需要写如下几个函数,用来判断和启动后台任务:

       

-(BOOL)isMultitaskingSupported {   // 判断设备是否支持后台任务
BOOL bResult = NO;
if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
{
bResult = [[UIDevice currentDevice] isMultitaskingSupported];
}
return bResult;
}
-(void)startbackgroundTask { // 启动后台任务,并记录任务id
CKPrint(@"startbackgroundTask");

m_taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{[self restartbackgroundTask];}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[Task bgTask:m_taskId];});
}
-(void)restartbackgroundTask { // 重启后台任务。由于ios中后台任务都是有时效性的,最长10分钟,然后还是会被系统给回收掉,所以需要个函数来重复启动任务
CKPrint(@"stopbackgroundTask");

// save old task id
UIBackgroundTaskIdentifier taskId = m_taskId;
m_taskId = UIBackgroundTaskInvalid;

// start new task
[self startbackgroundTask];

// stop old task
[[UIApplication sharedApplication] endBackgroundTask:taskId];
}

-(void)registerBackgroundTask { // 注册后台任务。这是唯一的入口函数,在applicationDidEnterBackground中调用,用来在APP退出时,启动后台任务
if ([self isMultitaskingSupported] == NO)
{
CKPrint(@"Don't support multitask");
return;
}

// the background has been run, and is not allowed to run again
if (m_bRun)
{
CKPrint(@"Task has been running");
return;
}

m_bRun = YES;
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{[self restartbackgroundTask];}]; //设置一个监听器,让系统在退出你的后台任务前,提前告诉你,然后执行你所指定的动作,这里我们设定在推出前,让其在启动一个后台任务,已保持任务的连续性
[self startbackgroundTask];
}
-(void)unregisterBackgroundTask { //唯一的出口函数。在你需要结束后台任务时,调用这个函数来结束后台任务
if (m_bRun == NO)
{
CKPrint(@"Task has been stoping");
return;
}

m_bRun = NO;
[[UIApplication sharedApplication] endBackgroundTask:m_taskId];
m_taskId = UIBackgroundTaskInvalid;
}
后台任务函数:

@implementation Task
+(void)bgTask:(UIBackgroundTaskIdentifier)taskId {
while (m_bRun)
{
// if start new task, then quit this task
if (m_taskId != taskId)// 因为后台任务会被系统强制回收掉,我们会重新启动一个新的后台任务,所以需要退出上一次的后台任务</span>
{
break;
}

NSLog(@"This is background execute. taskId=%d", taskId);
usleep(10 * 1000);
}
#endif
}
最后在applicationDidEnterBackground:(UIApplication*)application中写上如下代码,就完成了:

[viewController registerBackgroundTask];