¿Qué sucede si el usuario cierra una aplicación que ya está en segundo plano?

Durante una ejecución de tarea de background, ¿qué sucederá si el usuario destruye la aplicación (que ya está en modo de background)?

Imagínate esto:

La aplicación inicia la tarea X (con soporte de background de 10 minutos y un controller de caducidad al que se debe llamar). Luego, la aplicación pasa a segundo plano y el usuario mata la aplicación.

Estoy confundido sobre lo que sucederá con la tarea X después de que la aplicación sea asesinada. ¿Todavía tiene ese time de background para ejecutarse? ¿Se llama al manejador de caducidad?

Si la aplicación ya está "en segundo plano", ¡el usuario ya ha "cerrado la aplicación"! Entonces, ¿qué puede significar tu pregunta? Ya has entrado en segundo plano, y si beginBackgroundTaskWithExpirationHandler: mientras lo hacías, las cosas continúan normalmente.

¿Quieres decir que el usuario mata forzosamente la aplicación en segundo plano, invocando la interfaz de "aplicaciones recientes" y entrando en modo jiggy y eliminando la aplicación de la interfaz de "aplicaciones recientes"? Luego la aplicación es sumriamente asesinada; no recibes ninguna notificación y lo que sea que hagas está interrumpido.

Además, lo único que se supone que debe hacer el bloque de endBackgroundTask: es llamar a endBackgroundTask: Si lo matan sumriamente, ¡el hecho de que no pueda hacer esta llamada no es importante!

Ok, este es el resultado.

En este caso, el sistema operativo enviará una señal de SIGKILL al process de su aplicación y no se llamará a la aplicación.

A continuación se muestra mi interpretación de los documentos de Apple, el trabajo de adivinar y los resultados de Google.

En tal caso, a continuación se llamará al delegado del método de su request.

 - (void)applicationWillTerminate:(UIApplication *)application 

Cita de Apple Docs

Para aplicaciones que no son compatibles con la ejecución en segundo plano o que están vinculadas con iOS 3.xo anterior, este método siempre se invoca cuando el usuario abandona la aplicación. Para las aplicaciones que admiten la ejecución en segundo plano, este método generalmente no se llama cuando el usuario abandona la aplicación porque la aplicación simplemente se mueve al background en ese caso. Sin embargo, este método se puede invocar en situaciones donde la aplicación se ejecuta en segundo plano (no está suspendida) y el sistema necesita terminarlo por algún motivo.

Por lo tanto, tiene que usar el valor UIApplicationExitsOnSuspend en YES en su file Plist; de lo contrario, no hay ninguna garantía de que la aplicación WillTerminate: nunca se llamará. Es por eso que el documento se puede usar en.

No creo que se llame al bloque de control de vencimiento, aunque no estoy seguro.

Esto es bastante fácil de probar, así que acabo de hacerlo (en un iPhone 4S con iOS 6.1.3) usando el código que pegaré al final, lo que inicia una tarea en segundo plano en el método applicationDidEnterBackground del delegado de la applicationDidEnterBackground .

El resultado es sorprendente.

Cuando el usuario sale de la aplicación haciendo clic en el button Inicio, mata manualmente la aplicación (haciendo doble clic en Inicio, colocando objects en modo jiggy y presionando el ícono de cierre de la aplicación) ocurre lo siguiente:

  1. applicationWillTerminate se llama.
  2. Cuando termine la applicationWillTerminate Will Terminate, la ejecución de background finaliza, independientemente de cuánto time de ejecución haya dejado la tarea de background. La aplicación ha sido asesinada.

SIN EMBARGO..

Si organiza las cosas para que la applicationWillTerminate Will Terminate no salga después de haber sido invocada, como en el código siguiente, sucede lo siguiente, al less en mi configuration de testing, cuando la aplicación se destruye manualmente:

  1. La tarea de background de la aplicación continúa ejecutándose en segundo plano .
  2. Incluso cuando el time de ejecución de background asignado ha caducado, la tarea en segundo plano continúa ejecutándose, al igual que el código en applicationWillTerminate , hasta que ese método finaliza.

Esto es claramente un error: no debería poder continuar ejecutando el código para siempre, y no confiaría en que siempre funcione. Pero aquellos que han estado usando varios hacks para reproducir audio en segundo plano para mantener viva una aplicación pueden querer investigar. Me interesaría que otras personas prueben el código en diferentes versiones / dispositivos de iOS y obtengan los mismos resultados.

Código para AppDelegate.m en mi proyecto de testing:

 // // BTAppDelegate.m // BackgroundTest // // Created by David Fearon on 07/05/2013. // Copyright (c) 2013 David Fearon. All rights reserved. // #import "BTAppDelegate.h" @implementation BTAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSLog(@"application didFinishLaunchingWithOptions called"); // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"applicationWillResignActive: called"); } - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"applicationDidEnterBackground: called"); UIApplication* thisApp = [UIApplication shanetworkingApplication]; UIBackgroundTaskIdentifier __block task = [thisApp beginBackgroundTaskWithExpirationHandler:^{ }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self printTimeRemaining]; while(YES) { [NSThread sleepForTimeInterval:1.0]; [self printTimeRemaining]; } //[thisApp endBackgroundTask:task]; }); } -(void)printTimeRemaining{ NSLog(@"Background task time remaining: %f", [[UIApplication shanetworkingApplication] backgroundTimeRemaining]); } - (void)applicationWillEnterForeground:(UIApplication *)application { NSLog(@"applicationWillEnterForeground: called"); } - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"applicationDidBecomeActive: called"); } - (void)applicationWillTerminate:(UIApplication *)application { NSLog(@"applicationWillTerminate: called"); while(YES) { [NSThread sleepForTimeInterval:1.0]; NSLog(@"Still executing code in applicationWillTerminate."); } } @end