iPhone-背景调查事件



background location (4)

什么工作,什么不工作

目前还不完全清楚这些答案中的哪一个起作用,而且我浪费了大量时间来尝试这些答案。 所以这是我对每个策略的经验:

  1. VOIP hack - 有效,如果你不是VOIP应用程序,会让你被拒绝
  2. 递归beginBackgroundTask... - 不起作用。 它将在10分钟后退出。 即使您在评论中尝试修复(至少截至2012年11月30日的评论)。
  3. Silent Audio - 有效,但人们因此被拒绝了
  4. 本地/推送通知 - 在您的应用被唤醒之前需要用户互动
  5. 使用背景位置 - 工作 。 以下是详细信息:

基本上,您使用“位置”背景模式来保持您的应用程序在后台运行。 它确实有效,即使用户不允许位置更新。 即使用户按下主页按钮并启动另一个应用程序,您的应用程序仍将运行。 它也是一个电池滤水器,如果您的应用程序与位置无关,可能会在批准过程中延伸,但据我所知,这是唯一一个很有可能获得批准的解决方案。

以下是它的工作原理:

在你的plist集中:

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

然后引用CoreLocation框架(在Build Phases中)并在应用程序的某个地方添加此代码(在进入后台之前):

#import <CoreLocation/CoreLocation.h>

CLLocationManager* locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];

注意: startMonitoringSignificantLocationChanges不起作用。

值得一提的是,如果您的应用程序崩溃,那么iOS将无法恢复生命。 VOIP黑客是唯一可以带回来的黑客。

https://ffff65535.com

很长一段时间以来,我一直在寻找一种方法,在我的iPhone应用程序中每隔X分钟轮询一次以检查数据计数器。 在阅读了背景执行文档和一些试用版应用之后,我不认为这是不可能的,而不会滥用后台API。

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

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

有没有人知道如何实现这一目标?


在我对iOS5的测试中,我发现通过startMonitoringForLocationChangeEvents(而不是SignificantLocationChange)启动CoreLocation的监控是有帮助的,准确性无关紧要,如果我这样做,甚至在iPod上也是这样 - backgroundTimeRemaining永远不会失败。


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

如果您使用其中一个后台功能,那么一旦退出(由系统),该应用程序将再次由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-Time,你的应用程序运行时间更长! 但有一件事是肯定的:您的应用程序将在一段时间后终止。 但是因为您将应用程序注册为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功能背后的行为......


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





multitasking