Iphone setKeepAliveTimeout和BackgroundTasks

Iphone setKeepAliveTimeout和BackgroundTasks,iphone,objective-c,nsurlconnection,nsthread,objective-c-blocks,Iphone,Objective C,Nsurlconnection,Nsthread,Objective C Blocks,这个话题让我头痛不已。我正在开发一个需要定期轮询Web服务器以检查新数据的应用程序。根据返回的信息,我希望向用户推送一个本地通知 我知道这种方法与苹果公司描述的稍有不同,苹果公司使用远程服务器,基于APN推送远程通知。然而,有许多原因使我不能考虑这种方法。一个是用户身份验证机制。出于安全原因,远程服务器无法考虑用户凭据。我所能做的就是将登录和获取核心移动到客户端(iPhone) 我注意到苹果为应用程序提供了一个唤醒和保持套接字连接(即VoIP应用程序)打开的机会 所以,我就这样开始调查。在pli

这个话题让我头痛不已。我正在开发一个需要定期轮询Web服务器以检查新数据的应用程序。根据返回的信息,我希望向用户推送一个本地通知

我知道这种方法与苹果公司描述的稍有不同,苹果公司使用远程服务器,基于APN推送远程通知。然而,有许多原因使我不能考虑这种方法。一个是用户身份验证机制。出于安全原因,远程服务器无法考虑用户凭据。我所能做的就是将登录和获取核心移动到客户端(iPhone)

我注意到苹果为应用程序提供了一个唤醒和保持套接字连接(即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];
}];
NSO操作,然后使用以下块代码启动后台任务:

#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
异常类型:00000020
异常代码:0x8badf00d
突出显示的线程:3
特定于应用程序的信息:
DemoBackApp[5977]的活动断言超出了允许的时间:
{(
标识符:UIKitBackgroundCompletionTask进程:DemoBackApp[5977]permittedBackgroundDuration:600.000000原因:finishTask所有者pid:5977 preventSuspend preventIdleSleep
)}
已用CPU总时间(秒):0.010(用户0.010,系统0.000),100%CPU
已用应用程序CPU时间(秒):0.000,0%CPU
对于那些提出要求的人,是的。我也尝试过异步NSURLConnection方法。不管怎样即使我使用异步方法处理超时处理程序和didFinishLoading:WithError,它也会崩溃


我卡住了。非常感谢您的任何提示。

当您调用
-setKeepAliveTimeout:handler:
时,您最多只需30秒即可完成所有操作并挂起。您的后台宽限期与应用程序首次转换到后台时的宽限期不同。这意味着要完成长时间运行的任务,关闭东西,等等

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

另外,需要注意的是,如果您实际上不是VOIP应用程序,或者如果您在VOIP回调窗口中执行了与保持网络连接打开无关的任何操作,则应用商店将拒绝您的应用程序。当您设置任何保持活动的标志(VOIP、背景音乐、导航)时,他们会对其进行非常严格的测试,以确保它只在后台执行标记的操作。执行任何类型的HTTP GET请求并等待一些大型数据更新回来,几乎肯定会导致应用被拒绝


编辑:正如Patrick在评论中所指出的,在iOS 5中,当前给块执行的时间已从30秒减少到10秒。每当您重新链接应用程序以获取新版本的SDK时,最好注意这些时间,至少要快速检查文档,以防它们被更新(随着iOS 6的推出,这个数字可能会再次调整).

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

仍然存在与上述问题相同的问题——您需要在plist中使用VOIP标志进行提交,如果您具有该标志并且实际上不是VOIP应用程序,则Apple不太可能接受您的应用程序,但对于内部分发(企业或其他),此解决方案应该可以很好地为您提供后台时间

在我的测试中,每次调用VOIP处理程序时都会重置10分钟有限执行计时器(无论用户是否从此将应用程序带到前台),这意味着您可以在后台每600秒(10分钟)轮询一次服务器而轮询过程可能需要长达10分钟才能进入睡眠状态(这意味着,如果您需要的话,可以进行几乎连续的后台操作)


同样,除非你能说服他们你是VOIP,否则这不是应用商店的真正选项。

这是一个旧线程,但可能需要更新

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