Compartilhar via


Operação em segundo plano no iOS com tarefas

A maneira mais simples de executar o backgrounding no iOS é dividir seus requisitos de tela de fundo em tarefas e executar as tarefas em segundo plano. As tarefas estão sob um limite de tempo estrito e normalmente recebem cerca de 600 segundos (10 minutos) de tempo de processamento depois que um aplicativo é movido para o segundo plano no iOS 6 e menos de 10 minutos no iOS 7+.

As tarefas em segundo plano podem ser divididas em três categorias:

  1. Tarefas seguras em segundo plano – chamadas em qualquer lugar no aplicativo em que você tem uma tarefa que não deseja interromper caso o aplicativo insira em segundo plano.
  2. Tarefas didEnterBackground – chamadas durante o método de ciclo de vida do DidEnterBackground aplicativo para ajudar na limpeza e na economia de estado.
  3. Transferências em segundo plano (iOS 7+) – um tipo especial de tarefa em segundo plano usada para executar transferências de rede no iOS 7. Ao contrário das tarefas regulares, as transferências em segundo plano não têm um limite de tempo predeterminado.

Tarefas e DidEnterBackground segurança em segundo plano são seguras de usar no iOS 6 e no iOS 7, com algumas diferenças secundárias. Vamos investigar esses dois tipos de tarefas com mais detalhes.

Criando tarefas de Background-Safe

Alguns aplicativos contêm tarefas que não devem ser interrompidas pelo iOS caso o aplicativo altere o estado. Uma maneira de proteger essas tarefas de serem interrompidas é registrá-las no iOS como tarefas de execução prolongada. Você pode usar esse padrão em qualquer lugar em seu aplicativo em que não deseja que uma tarefa seja interrompida caso o usuário coloque o aplicativo em segundo plano. Um ótimo candidato para esse padrão seriam tarefas como enviar informações de registro de um novo usuário para o servidor ou verificar informações de logon.

O snippet de código a seguir demonstra o registro de uma tarefa a ser executada em segundo plano:

nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});

//runs on main or background thread
FinishLongRunningTask(taskID);

UIApplication.SharedApplication.EndBackgroundTask(taskID);

O processo de registro emparelha uma tarefa com um identificador exclusivo, e, em seguida, taskIDencapsula-a em correspondências BeginBackgroundTask e EndBackgroundTask chamadas. Para gerar o identificador, fazemos uma chamada para o BeginBackgroundTask método no objeto e, em UIApplication seguida, iniciamos a tarefa de execução longa, geralmente em um novo thread. Quando a tarefa for concluída, chamaremos EndBackgroundTask e transmitiremos o mesmo identificador. Isso é importante porque o iOS encerrará o aplicativo se uma BeginBackgroundTask chamada não tiver um correspondente EndBackgroundTask.

Importante

Tarefas seguras em segundo plano podem ser executadas no thread main ou em um thread em segundo plano, dependendo das necessidades do aplicativo.

Executando tarefas durante DidEnterBackground

Além de tornar uma tarefa de longa execução em segundo plano segura, o registro pode ser usado para iniciar tarefas, pois um aplicativo está sendo colocado em segundo plano. O iOS fornece um método de evento na classe AppDelegate chamada DidEnterBackground que pode ser usado para salvar o estado do aplicativo, salvar dados do usuário e criptografar conteúdo confidencial antes que um aplicativo entre em segundo plano. Um aplicativo tem aproximadamente cinco segundos para retornar desse método ou será encerrado. Portanto, tarefas de limpeza que podem levar mais de cinco segundos para serem concluídas podem ser chamadas de dentro do DidEnterBackground método . Essas tarefas devem ser invocadas em um thread separado.

O processo é quase idêntico ao de registrar uma tarefa de execução longa. O snippet de código a seguir ilustra isso em ação:

public override void DidEnterBackground (UIApplication application) {
  nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});
  new Task ( () => {
    DoWork();
    UIApplication.SharedApplication.EndBackgroundTask(taskID);
  }).Start();
}

Começamos substituindo o DidEnterBackground método no , em AppDelegateque registramos nossa tarefa por meio BeginBackgroundTask de como fizemos no exemplo anterior. Em seguida, geramos um novo thread e executamos nossa tarefa de execução prolongada. Observe que a EndBackgroundTask chamada agora é feita de dentro da tarefa de execução longa, já que o DidEnterBackground método já terá retornado.

Importante

O iOS usa um mecanismo watchdog para garantir que a interface do usuário de um aplicativo permaneça responsiva. Um aplicativo em DidEnterBackground que passa muito tempo ficará sem resposta na interface do usuário. Iniciar tarefas a serem executadas DidEnterBackground em segundo plano permite retornar em tempo hábil, mantendo a interface do usuário responsiva e impedindo que o cão de guarda mate o aplicativo.

Manipulando limites de tempo de tarefa em segundo plano

O iOS impõe limites rígidos sobre quanto tempo uma tarefa em segundo plano pode ser executada e, se a EndBackgroundTask chamada não for feita dentro do tempo alocado, o aplicativo será encerrado. Mantendo o controle do tempo restante em segundo plano e usando manipuladores de expiração quando necessário, podemos evitar que o iOS encerre o aplicativo.

Acessando o tempo restante em segundo plano

Se um aplicativo com tarefas registradas for movido para o plano de fundo, as tarefas registradas terão cerca de 600 segundos para serem executadas. Podemos marcar quanto tempo a tarefa tem para concluir usando a propriedade estática BackgroundTimeRemaining da UIApplication classe . O código a seguir nos dará o tempo, em segundos, que nossa tarefa em segundo plano deixou:

double timeRemaining = UIApplication.SharedApplication.BackgroundTimeRemaining;

Evitando terminação de aplicativo com manipuladores de expiração

Além de dar acesso à propriedade, o BackgroundTimeRemaining iOS fornece uma maneira normal de lidar com a expiração em segundo plano por meio de um Manipulador de Expiração. Esse é um bloco opcional de código que será executado quando o tempo alocado para uma tarefa estiver prestes a expirar. O código no Manipulador de Expiração chama EndBackgroundTask e passa a ID da tarefa, o que indica que o aplicativo está se comportando bem e impede que o iOS encerre o aplicativo mesmo se a tarefa ficar sem tempo. EndBackgroundTask deve ser chamado dentro do manipulador de expiração, bem como no curso normal da execução.

O manipulador de expiração é expresso como uma função anônima usando uma expressão lambda, conforme ilustrado abaixo:

Task.Factory.StartNew( () => {

    //expirationHandler only called if background time allowed exceeded
    var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => {
        Console.WriteLine("Exhausted time");
        UIApplication.SharedApplication.EndBackgroundTask(taskId); 
    });
    while(myFlag == true)
    {
        Console.WriteLine(UIApplication.SharedApplication.BackgroundTimeRemaining);
        myFlag = SomeCalculationNeedsMoreTime();
    }
    //Only called if loop terminated due to myFlag and not expiration of time
    UIApplication.SharedApplication.EndBackgroundTask(taskId);
});

Embora os manipuladores de expiração não sejam necessários para que o código seja executado, você sempre deve usar um manipulador de expiração com uma tarefa em segundo plano.

Tarefas em segundo plano no iOS 7+

A maior alteração no iOS 7 em relação às tarefas em segundo plano não é como as tarefas são implementadas, mas quando são executadas.

Lembre-se de que antes do iOS 7, uma tarefa em execução em segundo plano tinha 600 segundos para ser concluída. Um motivo para esse limite é que uma tarefa em execução em segundo plano manteria o dispositivo acordado durante a tarefa:

Grafo da tarefa mantendo o aplicativo acordado antes do iOS 7

O processamento em segundo plano do iOS 7 é otimizado para maior duração da bateria. No iOS 7, a tela de fundo torna-se oportunista: em vez de manter o dispositivo acordado, as tarefas respeitam quando o dispositivo entra em suspensão e, em vez disso, fazem o processamento em partes quando o dispositivo acorda para lidar com chamadas telefônicas, notificações, emails de entrada e outras interrupções comuns. O diagrama a seguir fornece informações sobre como uma tarefa pode ser dividida:

Grafo da tarefa que está sendo dividida em partes pós-iOS 7

Como o tempo de execução da tarefa não é mais contínuo, as tarefas que executam transferências de rede devem ser tratadas de forma diferente no iOS 7. Os desenvolvedores são incentivados a usar a NSURlSession API para lidar com transferências de rede. A próxima seção é uma visão geral das transferências em segundo plano.

Transferências em segundo plano

O backbone das transferências em segundo plano no iOS 7 é a nova NSURLSession API. NSURLSession nos permite criar tarefas para:

  1. Transfira conteúdo por meio de interrupções de rede e dispositivo.
  2. Carregar e baixar arquivos grandes ( Serviço de Transferência em Segundo Plano ).

Vamos dar uma olhada mais de perto em como isso funciona.

NSURLSession API

NSURLSession é uma API poderosa para transferir conteúdo pela rede. Ele fornece um conjunto de ferramentas para lidar com a transferência de dados por meio de interrupções de rede e alterações nos estados do aplicativo.

A NSURLSession API cria uma ou várias sessões, que, por sua vez, geram tarefas para transportar blocos de dados relacionados pela rede. As tarefas são executadas de forma assíncrona para transferir dados de forma rápida e confiável. Como NSURLSession é assíncrono, cada sessão requer um bloco de manipulador de conclusão para que o sistema e o aplicativo saibam quando uma transferência é concluída.

Para executar uma transferência de rede válida no pré-iOS 7 e pós-iOS 7, marcar se um NSURLSession estiver disponível para enfileirar transferências e usar uma tarefa em segundo plano regular para executar a transferência se não for:

if ([NSURLSession class]) {
  // Create a background session and enqueue transfers
}
else {
  // Start a background task and transfer directly
  // Do NOT make calls to update the UI here!
}

Importante

Evite fazer chamadas para atualizar a interface do usuário em segundo plano no código em conformidade com o iOS 6, pois o iOS 6 não dá suporte a atualizações de interface do usuário em segundo plano e encerrará o aplicativo.

A NSURLSession API inclui um conjunto avançado de recursos para lidar com a autenticação, gerenciar transferências com falha e relatar erros do lado do cliente , mas não do lado do servidor. Ele ajuda a fazer a ponte entre as interrupções no tempo de execução da tarefa introduzido no iOS 7 e também fornece suporte para transferir arquivos grandes de forma rápida e confiável. A próxima seção explora esse segundo recurso.

Serviço de Transferência em Segundo Plano

Antes do iOS 7, o carregamento ou o download de arquivos em segundo plano não era confiável. As tarefas em segundo plano têm um tempo limitado para serem executadas, mas o tempo necessário para transferir um arquivo varia de acordo com a rede e o tamanho do arquivo. No iOS 7, podemos usar um NSURLSession para carregar e baixar arquivos grandes com êxito. O tipo de sessão específico NSURLSession que manipula transferências de rede de arquivos grandes em segundo plano é conhecido como o Serviço de Transferência em Segundo Plano.

As transferências iniciadas usando o Serviço de Transferência em Segundo Plano são gerenciadas pelo sistema operacional e fornecem APIs para lidar com autenticação e erros. Como as transferências não estão associadas a um limite de tempo arbitrário, elas podem ser usadas para carregar ou baixar arquivos grandes, atualizar automaticamente o conteúdo em segundo plano e muito mais. Consulte o Passo a passo de transferência em segundo plano para obter detalhes sobre como implementar o Serviço.

O Serviço de Transferência em Segundo Plano geralmente é emparelhado com Busca em Segundo Plano ou Notificações Remotas para ajudar os aplicativos a atualizar o conteúdo em segundo plano. Nas próximas duas seções, apresentamos o conceito de registrar aplicativos inteiros para serem executados em segundo plano no iOS 6 e no iOS 7.