很长一段时间以来,我一直在寻找一种方法,在我的iPhone应用程序中每隔X分钟轮询一次,检查数据计数器。在阅读了背景执行文档和一些试用版应用之后,我不认为这是不可能的,而不会滥用后台API。
上周我发现这个应用程序正是如此。 http://itunes.apple.com/us/app/dataman-real-time-data-usage/id393282873?mt=8
它在后台运行并跟踪您使用的蜂窝/ WiFi数据的数量。我怀疑开发人员正在注册他的应用程序作为跟踪位置更改但在应用程序运行时看不到位置服务图标,我认为这是一项要求。
有没有人知道如何实现这一目标?
我也看到过这种行为。在尝试了很多之后,我发现了两件事,这可能有所帮助。但我仍然不确定这可能如何影响审查过程。
如果您使用其中一个后台功能,那么一旦退出(由系统),该应用程序将再次由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套接字。但是这10分钟的回调提供了一个很好的副作用:在10分钟之后(有时更早),我发现我的计时器和之前的跑步踏板正在执行一段时间。如果在代码中放置一些NSLog(..),就可以看到这一点。这意味着,这个简短的“唤醒”会执行一段时间的代码。根据Apple的说法,我们还有30秒的执行时间。我假设,像线程这样的后台代码正在执行近30秒。如果您必须“有时”检查某些内容,这是有用的代码。
该文档说,如果应用程序终止,所有后台任务(VoIP,音频,位置更新)将在后台自动重新启动。 VoIP应用程序将在启动后自动启动后台!
滥用此行为,您可以使您的应用看起来像“永远”运行。注册一个后台进程(即VoIP)。这将导致您的应用在终止后重新启动。
现在写一些“任务必须完成”的代码。根据Apple的说法,你还有一段时间(5秒钟?)来完成任务。我发现,这必须是CPU时间。这意味着:如果你什么都不做,你的应用程序仍在执行中!如果你完成了你的工作,Apple建议召唤一个expirationhandler。在下面的代码中,您可以看到,我在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秒后终止。但是会再次调用到期处理程序,它会启动另一个长时间运行的任务,等等。现在你只需要检查应用程序回到前台的天气。然后关闭bgTask,你就完成了。也许一个人可以做某事。像这样在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
// i.e.
// - (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'块)。通过将块定义为块变量,可以在到期处理程序中再次递归地启动长时间运行的任务。这也导致无休止的执行。
如果您的应用程序再次进入前台,请注意终止任务。如果您不再需要它,请终止任务。
根据我自己的经验,我测量了一些东使用GPS收音机打开的位置回调非常快地吸收我的电池。使用我在Update 2中发布的方法几乎没有能量。根据“userexperience”,这是一种更好的方法。也许其他应用程序的工作方式如下,隐藏了GPS功能背后的行为......
目前还不完全清楚这些答案中的哪一个起作用,而且我浪费了很多时间来尝试它们。所以这是我对每个策略的经验:
beginBackgroundTask...
- 不起作用。它会在10分钟后退出。即使您在评论中尝试修复(至少截至2012年11月30日的评论)。基本上,您使用“位置”后台模式来保持您的应用程序在后台运行。它确实有效,即使用户不允许位置更新。即使用户按下主页按钮并启动另一个应用程序,您的应用程序仍将运行。它也是一个电池滤水器,如果您的应用程序与位置无关,可能会在批准过程中延伸,但据我所知,这是唯一一个很有可能获得批准的解决方案。
以下是它的工作原理:
在你的plist集合中:
然后引用CoreLocation框架(在Build Phases中)并在应用程序的某个地方添加此代码(在进入后台之前):
#import <CoreLocation/CoreLocation.h>
CLLocationManager* locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
注意:startMonitoringSignificantLocationChanges
不起作用。
值得一提的是,如果您的应用程序崩溃,那么iOS将无法恢复生命。 VOIP黑客是唯一可以带回来的黑客。
还有另一种技术永远留在后台 - 在后台任务中启动/停止位置管理器,将在调用didUpdateToLocation:时重置后台计时器。
我不知道它为什么会起作用,但我认为didUpdateToLocation也被称为任务,从而重置了计时器。
基于测试,我相信这就是DataMan Pro所使用的。
看到这篇文章qazxsw点我从哪里获得技巧。
以下是我们的应用程序的一些结果:
https://stackoverflow.com/a/6465280
如果它不是GPS,我认为唯一的另一种方法就是背景音乐功能,即一直播放4“33”。两者听起来都像是滥用后台处理API,因此可能会受到审核流程的影响。
我尝试了更新2,但它不起作用。调用到期处理程序时,它将结束后台任务。然后启动一个新的后台任务只会强制立即再次调用到期处理程序(计时器未重置且仍然过期)。因此,在应用程序暂停之前,我有43次启动/停止后台任务。
在我对iOS5的测试中,我发现通过startMonitoringForLocationChangeEvents(而不是SignificantLocationChange)启动CoreLocation的监控是有帮助的,准确性并不重要,如果我这样做,甚至在iPod上也是这样 - backgroundTimeRemaining永远不会失效。
这是一个相当古老的问题,但现在正确的方法是通过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
,它完全由操作系统支持,不需要任何黑客攻击。
请注意,在实际进行后台刷新时,您仍然受操作系统的支配。您可以设置最小轮询时间,但不能保证在该频率下调用它,因为操作系统将应用自己的逻辑来优化电池寿命和无线电使用。
您需要做的第一件事是在“功能”选项卡中配置项目以支持后台刷新。这将为你的Background App Refresh添加必要的键:
Info.plist
然后你需要添加一些东西到你的,这需要实现AppDelegate
和URLSessionDelegate
:
URLSessionDownloadDelegate