iPhone – 背景调查事件

有一段时间我一直在我的iPhone应用程序中查找一个方法来轮询每X分钟来检查数据计数器。 在仔细阅读了后台执行文档和几个试用版应用程序后,我认为这是不可能的,而不会滥用后台API。

上周我发现这个应用程序正是这样做的。 http://itunes.apple.com/us/app/dataman-real-time-data-usage/id393282873?mt=8

它在后台运行,并跟踪您使用的蜂窝/ WiFi数据的数量。 我怀疑开发人员正在注册他的应用程序作为跟踪位置更改,但位置服务图标不显示,而应用程序正在运行,我认为这是一个要求。

有没有人有任何线索可以做到这一点?

我也看到了这种行为。 经过多次尝试,我发现了两件事情,这可能有帮助。 但我仍然不确定这可能会如何影响审查过程。

如果您使用其中一种背景function,应用程序一旦退出(由系统),将在后台由iOS启动。 这个我们以后会滥用的。

在我的情况下,我用我的plist启用了VoIP背景。 所有的代码都在你的AppDelegate中完成:

// if the iOS device allows background execution, // this Handler will be called - (void)backgroundHandler { NSLog(@"### -->VOIP backgrounding callback"); // try to do sth. According to Apple we have ONLY 30 seconds to perform this Task! // Else the Application will be terminated! UIApplication* app = [UIApplication sharedApplication]; NSArray* oldNotifications = [app scheduledLocalNotifications]; // Clear out the old notification before scheduling a new one. if ([oldNotifications count] > 0) [app cancelAllLocalNotifications]; // Create a new notification UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease]; if (alarm) { alarm.fireDate = [NSDate date]; alarm.timeZone = [NSTimeZone defaultTimeZone]; alarm.repeatInterval = 0; alarm.soundName = @"alarmsound.caf"; alarm.alertBody = @"Don't Panic! This is just a Push-Notification Test."; [app scheduleLocalNotification:alarm]; } } 

并且注册完成在

 - (void)applicationDidEnterBackground:(UIApplication *)application { // This is where you can do your X Minutes, if >= 10Minutes is okay. BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }]; if (backgroundAccepted) { NSLog(@"VOIP backgrounding accepted"); } } 

现在魔术发生了:我甚至不使用VoIP-Sockets。 但这10分钟的callback提供了一个很好的副作用:10分钟后(有时更早),我发现我的计时器和以前的跑步步伐正在执行一会儿。 你可以看到这个,如果你把一些NSLog(..)放入代码中。 这意味着,这个短暂的“唤醒”执行一段时间的代码。 根据苹果,我们有30秒的执行时间。 我认为,像线程这样的后台代码正在执行近30秒。 这是有用的代码,如果你必须“有时”检查一些东西。

该文件说,如果应用程序被终止,所有后台任务(VoIP,audio,位置更新)将在后台自动重新启动。 启动后VoIP应用程序将在后台自动启动!

随着滥用这种行为,你可以让你的应用程序看起来像运行“永远”。 注册一个后台进程(即VoIP)。 这将导致您的应用在终止后重新启动。

现在写一些“任务必须完成”的代码。 据苹果公司说,你还有一段时间(5秒?)完成任务。 我发现,这一定是CPU时间。 这意味着:如果你什么都不做,你的应用程序仍在执行中! 如果你完成了你的工作,苹果build议打电话过期处理程序。 在下面的代码中,您可以看到,我在expirationHandler中有一个注释。 只要系统允许您的应用程序运行,这将导致您的应用程序运行。 所有的计时器和线程都保持运行,直到iOS终止你的应用程序。

 - (void)applicationDidEnterBackground:(UIApplication *)application { UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // Start the long-running task and return immediately. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // you can do sth. here, or simply do nothing! // All your background treads and timers are still being executed while (background) [self doSomething]; // This is where you can do your "X minutes" in seconds (here 10) sleep(10); } // And never call the expirationHandler, so your App runs // until the system terminates our process //[app endBackgroundTask:bgTask]; //bgTask = UIBackgroundTaskInvalid; }); } 

在这里CPU时间非常闲,你的应用程序运行更长! 但有一件事是肯定的:你的应用程序将在一段时间后终止。 但是,因为你注册你的应用程序为VoIP或其他之一,系统重新启动应用程序在后台,这将重新启动您的后台进程;-)有了这个PingPong我可以做很多背景。 但要记住CPU时间非常多。 并保存所有数据,恢复您的意见 – 您的应用程序将在一段时间后终止。 为了使它看起来仍然在运行,你必须在唤醒后跳回到上一个“状态”。

我不知道这是否是您之前提到的应用程序的方法,但它适用于我。

希望我能帮上忙

更新:

在测量BG任务的时间之后,出现了一个惊喜。 BG任务限制为600秒。 这是VoIP最短时间的确切最短时间(setKeepAliveTimeout:600)。

所以这个代码在后台导致“无限”执行:

标题:

 UIBackgroundTaskIdentifier bgTask; 

码:

 // if the iOS device allows background execution, // this Handler will be called - (void)backgroundHandler { NSLog(@"### -->VOIP backgrounding callback"); UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // Start the long-running task dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (1) { NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining); [self doSomething]; sleep(1); } }); - (void)applicationDidEnterBackground:(UIApplication *)application { BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }]; if (backgroundAccepted) { NSLog(@"VOIP backgrounding accepted"); } UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // Start the long-running task dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (1) { NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining); [self doSomething]; sleep(1); } }); } 

在您的应用程序超时后,将调用VoIP expirationHandler,您只需重新启动长时间运行的任务即可。 该任务将在600秒后终止。 但是会再次调用过期处理程序,这会启动另一个长时间运行的任务,等等。现在,您只需检查App是否回到前台。 然后closuresbgTask,就完成了。 也许可以做某事 从长期运行的任务中,像这个在expirationHandler里面。 试试吧。 使用您的控制台,看看会发生什么…玩得开心!

更新2:

有时简化的事情有助于。 我的新方法是这样的:

 - (void)applicationDidEnterBackground:(UIApplication *)application { UIApplication* app = [UIApplication sharedApplication]; // it's better to move "dispatch_block_t expirationHandler" // into your headerfile and initialize the code somewhere else // ie // - (void)applicationDidFinishLaunching:(UIApplication *)application { // // expirationHandler = ^{ ... } } // because your app may crash if you initialize expirationHandler twice. dispatch_block_t expirationHandler; expirationHandler = ^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler]; }; bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler]; // Start the long-running task and return immediately. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // inform others to stop tasks, if you like [[NSNotificationCenter defaultCenter] postNotificationName:@"MyApplicationEntersBackground" object:self]; // do your background work here }); } 

这是没有 VoIP黑客工作。 根据文档,到期处理程序(在这种情况下,我的'expirationHandler'块)将执行,如果执行时间结束。 通过将块定义为块variables,可以在到期处理程序中再次recursion地启动长时间运行的任务。 这也导致了无尽的执行。

如果您的应用程序再次进入前台,请注意终止任务。 如果你不再需要,终止任务。

根据我自己的经验,我测量了一些 在使用GPS无线电的情况下使用位置callback会非常快速地吸住电池。 使用我在Update 2中发布的方法几乎没有任何能量。 根据“userexperience”这是一个更好的方法。 也许其他应用程序是这样工作的,隐藏它的GPSfunction后面的行为…

什么工作,什么不工作

这些答案中的哪一个并不完全清楚,我浪费了大量的时间去尝试。 所以这里是我的每个策略的经验:

  1. VOIP黑客 – 工作,但会让你被拒绝,如果你不是一个VOIP应用程序
  2. recursionbeginBackgroundTask... – 不起作用。 10分钟后退出。 即使您在评论中尝试修复(至less在截至2012年11月30日的评论中)。
  3. 沉默的audio – 作品,但人们被拒绝了
  4. 本地/推送通知 – 在您的应用程序被唤醒之前需要用户进行交互
  5. 使用背景位置 – 工作 。 以下是详细信息:

基本上你使用“位置”的背景模式,让你的应用程序在后台运行。 它可以工作,即使用户不允许位置更新。 即使用户按下主页button并启动另一个应用程序,您的应用程序仍将继续运行。 这也是一个电池filter,如果你的应用程序与位置无关,可能是审批过程中的一个延伸,但据我所知,这是唯一的解决scheme,有很大的机会获得批准。

这是如何工作的:

在你的plist集:

  • 应用程序不会在后台运行:NO
  • 所需的背景模式:位置

然后引用CoreLocation框架(在构build阶段),并将其添加到应用程序的某个位置(在进入后台之前):

 #import <CoreLocation/CoreLocation.h> CLLocationManager* locationManager = [[CLLocationManager alloc] init]; [locationManager startUpdatingLocation]; 

注意: startMonitoringSignificantLocationChanges将不起作用。

另外值得一提的是,如果你的应用程序崩溃,那么iOS不会重新启动。 VOIP黑客是唯一可以把它带回来的。

还有另外一种技术可以永久保留在后台 – 在后台任务中启动/停止位置pipe理器,didUpdateToLocation:被调用时,会重置后台计时器。

我不知道为什么它的工作原理,但我认为didUpdateToLocation也被称为一个任务,从而重置计时器。

基于testing,我相信这是DataMan Pro正在使用的。

看到这个posthttps://stackoverflow.com/a/6465280我从哪里得到了诀窍。

以下是我们的应用程序的一些结果:

 2012-02-06 15:21:01.520 **[1166:4027] BGTime left: 598.614497 2012-02-06 15:21:02.897 **[1166:4027] BGTime left: 597.237567 2012-02-06 15:21:04.106 **[1166:4027] BGTime left: 596.028215 2012-02-06 15:21:05.306 **[1166:4027] BGTime left: 594.828474 2012-02-06 15:21:06.515 **[1166:4027] BGTime left: 593.619191 2012-02-06 15:21:07.739 **[1166:4027] BGTime left: 592.395392 2012-02-06 15:21:08.941 **[1166:4027] BGTime left: 591.193865 2012-02-06 15:21:10.134 **[1166:4027] BGTime left: 590.001071 2012-02-06 15:21:11.339 **[1166:4027] BGTime left: 588.795573 2012-02-06 15:21:11.351 **[1166:707] startUpdatingLocation 2012-02-06 15:21:11.543 **[1166:707] didUpdateToLocation 2012-02-06 15:21:11.623 **[1166:707] stopUpdatingLocation 2012-02-06 15:21:13.050 **[1166:4027] BGTime left: 599.701993 2012-02-06 15:21:14.286 **[1166:4027] BGTime left: 598.465553 

我尝试了更新2,但它不工作。 到期处理程序被调用时,结束后台任务。 然后开始一个新的后台任务只是强制立即再次呼叫到期处理程序(定时器不重置,仍然过期)。 因此,在应用被暂停之前,我有43次启动/停止后台任务。

如果不是GPS,我认为唯一的方法就是背景音乐function,即一直播放4“33”。 这听起来像是对后台处理API的滥用,因此可能受到审查过程的突发事件的影响。

在我对iOS5的testing中,我发现通过startMonitoringForLocationChangeEvents(而不是SignificantLocationChange)启动CoreLocation的监控是有帮助的,精确度无关紧要,甚至在iPod上这种方式也是如此 – backgroundTimeRemaining永远不会下降。