setKeepAliveTimeout和BackgroundTasks

时间:2011-01-24 00:16:25

标签: iphone objective-c nsurlconnection nsthread objective-c-blocks

我对这个话题非常头疼。我正在开发一个需要定期轮询网络服务器的应用程序,以便检查新数据。根据返回的信息,我希望将本地通知推送给用户。

我知道这种方法与Apple描述的方法略有不同,其中远程服务器根据APNS进行工作,推送远程通知。但是,我有很多理由不能考虑这种方法。一个是用户身份验证机制。出于安全原因,远程服务器无法考虑用户凭据。我所能做的就是将登录和获取核心移动到客户端(iPhone)。

我注意到Apple为应用程序提供了唤醒并保持打开Socket连接(即VoIP应用程序)的机会。

所以,我开始以这种方式进行调查。在plist中添加了所需的信息,我能够“唤醒”我的应用程序,在我的appDelegate中使用类似的东西:

[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{ 
    NSLog(@"startingKeepAliveTimeout");
    [self contentViewLog:@"startingKeepAliveTimeout"];
    MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
    [queue addOperation:op];
    [op release];
}];

NSOperation然后使用以下块代码启动后台任务:

#pragma mark SyncRequests
-(void) main {
    NSLog(@"startSyncRequest");
    [self contentViewLog:@"startSyncRequest"];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        NSLog(@"exipiration handler triggered");
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
        [self cancel];
    }];


        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSMutableURLRequest *anURLRequest;
            NSURLResponse *outResponse;
            NSError *exitError;
            NSString *username;
            NSString *password;

            NSLog(@"FirstLogin");
            anURLRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:webserverLogin, username, password]]];
            [anURLRequest setHTTPMethod:@"GET"];
            [anURLRequest setTimeoutInterval:120.00];
            [anURLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];

            exitError = nil;
            NSData *tmpData = [NSURLConnection sendSynchronousRequest:anURLRequest returningResponse:&outResponse error:&exitError];
            [anURLRequest setTimeoutInterval:120.00];
            if(exitError != nil) { //somethings goes wrong
                NSLog(@"somethings goes wrong");
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
                [self cancel];
                return;
            }

            //do some stuff with NSData and prompt the user with a UILocalNotification

            NSLog(@"AlltasksCompleted");
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
            [self cancel];
        });
    }
}

上面的代码似乎有效(有时),但是很多其他代码会崩溃我的应用程序,并带有以下日志信息:

Exception Type:  00000020
Exception Codes: 0x8badf00d
Highlighted Thread:  3

Application Specific Information:
DemoBackApp[5977] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0xa9da0b0> identifier: UIKitBackgroundCompletionTask process: DemoBackApp[5977] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:5977 preventSuspend  preventIdleSleep 
)}

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU

对于那些问,是的。我也尝试过Async NSURLConnection方法。不管。即使我使用带有超时处理程序的异步方法和didFinishLoading:WithError,它也会崩溃。

我被困住了。任何提示都受到高度赞赏。

4 个答案:

答案 0 :(得分:9)

这是一个旧帖子,但可能需要更新。

从iOS 6开始,这是我通过此线程中讨论的VoIP计时器后台方法看到的行为:

  • 仍然严格禁止通过App Review流程从AppStore应用程序中禁用VoIP BackgroundMode
  • 最小KeepAlive时间为600秒;任何小于此的东西都会导致处理程序无法安装(并向NSLog发送警告)
  • 将keepAlive时间设置为远大于600秒的时间通常会导致处理程序以每时间/ 2 间隔的频率触发。额外事实:这与SIP REGISTER请求一致,其中推荐的重新注册间隔为.5 *重新注册时间。
  • 调用keepAlive处理程序时,我观察到以下内容:
    • 你得到的是 10秒&#34;前景&#34;执行时间,其中剩余的背景时间是无限的(由 backgroundTimeRemaining 返回)
    • 如果你从keepAlive处理程序中启动 beginBackgroundTask ,我发现你得到 60秒的后台执行时间(由 backgroundTimeRemaining <返回< /强>)。 这与用户从处于活动状态的应用转换为背景时获得的 600秒不同。我没有找到任何方法来延长此时间(不使用其他技巧)喜欢位置等。)

希望有所帮助!

答案 1 :(得分:7)

当您致电-setKeepAliveTimeout:handler:时,您只需最多30秒即可完成所有操作并暂停。当您的应用程序首次转换为后台时,您将获得相同的背景宽限期。这意味着完成长时间运行的任务,关闭事情等等。

使用VOIP回调,您应该发送需要发送到服务的任何ping数据包,以保持网络连接的活跃状态,而不是超时。 30秒后,无论是否启动新的后台任务,如果您的应用程序仍在执行,您将被终止。

此外,重要的是要注意,如果您实际上不是VOIP应用程序,如果您在VOIP回调窗口期间执行任何与保持网络连接无关的任何内容,那么您的应用 从应用商店中被拒绝。当你设置任何保持活动标志(VOIP,背景音乐,导航)时,他们会非常严格地测试它,以确保执行它在后台标记要执行的操作。执行任何类型的HTTP GET请求并等待一些大型数据更新回来几乎可以保证您的应用程序被拒绝。

编辑:正如帕特里克在评论中指出的那样,使用iOS 5,当前执行块的时间从30秒减少到10秒。每当你关注这些时间时,这是一个好主意。重新链接您的应用程序以获得新版本的SDK,如果文档已经更新,请至少快速检查文档(iOS 6即将推出,这个数字可能会再次调整)。

答案 2 :(得分:6)

只是为iOS7更新此行为。

  • 当您的应用首次进入后台时,您将获得180秒的时间 backgroundTimeRemaining报告的任务时间。然而,它停止了 在此时间之前5秒响应,如报告所示 backgroundTimeRemaining。
  • 当keepAlive任务触发时,backgroundTimeRemaining为10 前景的秒数,然后是60秒的后台计时器 由backgroundTimeRemaining报道。它也会在此时间用完之前5秒停止响应,如backgroundTimeRemaining报告的那样。

因此,在iOS7上,您每10分钟可以获得65秒的处理时间。

答案 3 :(得分:3)

似乎您可以通过在被调用时捎带有限后台任务执行请求来组合保持活动超时处理程序。每次VOIP保持活动处理程序被调用时,这将允许你整整10分钟(通常是10-30秒)。

仍然和上面一样的问题 - 你需要提交你的plist中的VOIP标志,如果你有那个标志并且实际上不是VOIP应用程序,Apple不可能接受你的应用程序,但是内部分发(企业或其他),此解决方案应该可以正常工作,为您提供后台时间。

在我的测试中,每次调用VOIP处理程序时都会重置10分钟的有限执行计时器(无论用户是否从那时起将应用程序带到前面),这应该意味着您可以无限期地轮询您的服务器而在背景中每600秒(10分钟)一次,并且轮询过程最多可能需要10分钟才能进入睡眠状态(这意味着几乎不变的背景操作,如果这是您所需要的)。

同样,除非你能说服他们你是VOIP,否则不是App Store的一个选项。