setKeepAliveTimeout e BackgroundTasks
Estou com uma grande dor de cabeça com o tópico. Estou trabalhando em um aplicativo que precisa pesquisar regularmente um servidor da web, a fim de verificar novos dados. Com base nas informações retornadas, desejo enviar uma notificação local ao usuário.
Eu sei que essa abordagem é um pouco diferente da descrita pela Apple, na qual um servidor remoto faz o trabalho, enviando uma notificação remota, com base no APNS. No entanto, existem muitas razões pelas quais não posso levar essa abordagem em consideração. Um por todos, é o mecanismo de autenticação do usuário. O servidor remoto, por motivos de segurança, não pode levar em consideração as credenciais do usuário. Tudo o que posso fazer é mover o núcleo de login e busca, para o cliente (iPhone).
Notei que a Apple oferece uma oportunidade para os aplicativos serem ativados e manterem aberta uma conexão Socket (ou seja, um aplicativo VoIP).
Então, comecei a investigar dessa maneira. Adicionadas as informações necessárias no plist, sou capaz de "acordar" meu aplicativo, usando algo parecido com isso no meu appDelegate:
[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{
NSLog(@"startingKeepAliveTimeout");
[self contentViewLog:@"startingKeepAliveTimeout"];
MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
[queue addOperation:op];
[op release];
}];
O NSOperation, em seguida, inicia uma tarefa em segundo plano usando o seguinte código de bloco:
#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];
});
}
}
O código acima parece funcionar (algumas vezes), mas muitos outros travam meu aplicativo, com as seguintes informações de log:
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
Para quem pergunta, sim. Também tentei a abordagem Async NSURLConnection. Não importa. Ele trava da mesma forma, mesmo se eu usar uma abordagem assíncrona com o manipulador de tempo limite e didFinishLoading: WithError.
Estou preso. Todas as dicas são muito apreciadas.