J'ai vu ce comportement, trop. Après avoir essayé beaucoup, j'ai découvert deux choses, ce qui pourrait l'aider. Mais je ne suis toujours pas sûr de savoir comment cela peut influencer le processus de révision.
Si vous utilisez l'un de la semi-finition des fonctionnalités, l'application sera lancée par iOS en arrière-plan encore une fois, c'était quitter (par le système). Cela nous permettra d'abus.
Dans mon cas, j'ai utilisé la VoIP, la semi-finition activé dans mon plist.
Tout le code ici est fait dans votre AppDelegate:
// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {
NSLog(@"### -->VOIP backgrounding callback");
// try to do sth. According to Apple we have ONLY 30 seconds to perform this Task!
// Else the Application will be terminated!
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0) [app cancelAllLocalNotifications];
// Create a new notification
UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
if (alarm)
{
alarm.fireDate = [NSDate date];
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = @"alarmsound.caf";
alarm.alertBody = @"Don't Panic! This is just a Push-Notification Test.";
[app scheduleLocalNotification:alarm];
}
}
et que l'enregistrement est fait dans
- (void)applicationDidEnterBackground:(UIApplication *)application {
// This is where you can do your X Minutes, if >= 10Minutes is okay.
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
{
NSLog(@"VOIP backgrounding accepted");
}
}
Maintenant que la magie se produit: je n'ai pas encore utiliser la VoIP-Sockets. Mais ces 10 Minutes de rappel fournit un bel effet: au bout de 10 Minutes (parfois plus tôt), j'ai découvert que mon minuteries et de fonctionnement des bandes de roulement en cours d'exécution pendant un court instant. Vous pouvez le voir, si vous placez certains NSLog(..) dans votre code. Cela signifie, que ce petit "réveil" exécute le code pour un certain temps. Selon Apple, nous avons 30 secondes de temps d'exécution à gauche. Je suppose, que l'arrière-plan d'un code comme les threads en cours d'exécution pendant près de 30 secondes. Ceci est utile de code, si vous devez "parfois" vérifier quelque chose.
Le doc a dit que toutes les tâches en arrière-plan (VoIP, de l'audio, de l'emplacement des mises à jour) sera redémarré automatiquement en arrière-plan si l'application a été résilié. VoIP applications sera lancé en arrière-plan automatiquement après le démarrage!
D'abuser de ce comportement, vous pouvez rendre votre application d'être à la recherche, comme la course "pour toujours".
Inscrivez-vous à un processus d'arrière-plan (c'est à dire VoIP). Ce sera la cause de votre application d'être redémarré après la résiliation.
Maintenant écrire un peu "Tâche doit être terminée" du code. Selon Apple, vous avez un peu de temps (5 secondes?) de gauche à terminer les tâches. J'ai découvert, que ce doit être le temps CPU. Cela signifie: si vous ne faites rien, votre application est toujours d'être exécuté! Apple suggèrent de faire appel à une expirationhandler, si vous avez fini votre travail. Dans le code ci-dessous, vous pouvez voir que j'ai un commentaire à la expirationHandler. Ce sera la cause de votre application qui s'exécute tant que le système permet à votre application d'être en cours d'exécution. Tous les compteurs à zéro et fils reste en cours d'exécution jusqu'à ce que iOS met fin à votre application.
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// you can do sth. here, or simply do nothing!
// All your background treads and timers are still being executed
while (background)
[self doSomething];
// This is where you can do your "X minutes" in seconds (here 10)
sleep(10);
}
// And never call the expirationHandler, so your App runs
// until the system terminates our process
//[app endBackgroundTask:bgTask];
//bgTask = UIBackgroundTaskInvalid;
});
}
Être très rechange avec CPU-Temps ici, et que votre application fonctionne plus! Mais une chose est sûre: votre application sera résilié après un certain temps. Mais parce que vous avez enregistré votre application comme la VoIP ou l'une de l'autre, le système redémarre l'application en arrière-plan, ce qui permet de redémarrer votre processus d'arrière-plan ;-)
Avec ce ping-pong que je peux faire beaucoup de semi-finition. mais rappelez-vous d'être très rechange avec le temps CPU. Et d'enregistrer toutes les données, afin de restaurer vos points de vue - votre application va être arrêté quelque temps plus tard. Pour la faire apparaître toujours en cours d'exécution, vous devez revenir en arrière dans votre dernier "état" après le réveil.
Je ne sais pas si c'est l'approche des apps que vous avez mentionné avant, mais cela fonctionne pour moi.
J'espère que je pourrais aider
Mise à jour:
Après la mesure, le temps de la tâche BG, il y avait une surprise. Le BG Tâche est limitée à 600 secondes. C'est exactement le temps minimum de la VoIP minimumtime (setKeepAliveTimeout:600).
Donc CE code mène à "l'infini" exécution en arrière-plan:
En-tête:
UIBackgroundTaskIdentifier bgTask;
Code:
// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {
NSLog(@"### -->VOIP backgrounding callback");
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
- (void)applicationDidEnterBackground:(UIApplication *)application {
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
{
NSLog(@"VOIP backgrounding accepted");
}
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
}
Une fois que votre application a expiré, la VoIP expirationHandler sera appelée, où il vous suffit de redémarrer une longue tâche en cours d'exécution. Cette tâche sera terminée après 600 secondes. Mais il y aura de nouveau un appel à l'expiration d'un délai de gestionnaire, qui commence une longue tâche en cours d'exécution, etc. Maintenant, vous n'avez qu'à vérifier la météo de l'Application est de revenir au premier plan. Puis fermez le bgTask, et vous avez terminé. Peut-être on peut faire qqch. comme ça à l'intérieur de la expirationHandler de la longue tâche en cours d'exécution. Il suffit de l'essayer. Utilisez votre Console, pour voir ce qui se passe... amusez-vous!
Mise à jour 2:
Parfois, permet de simplifier les choses. Ma nouvelle approche est celle-ci:
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication* app = [UIApplication sharedApplication];
// it's better to move "dispatch_block_t expirationHandler"
// into your headerfile and initialize the code somewhere else
// i.e.
// - (void)applicationDidFinishLaunching:(UIApplication *)application {
//
// expirationHandler = ^{ ... } }
// because your app may crash if you initialize expirationHandler twice.
dispatch_block_t expirationHandler;
expirationHandler = ^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
};
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// inform others to stop tasks, if you like
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyApplicationEntersBackground" object:self];
// do your background work here
});
}
Ce travail est sans la VoIP hack. Selon la documentation, à l'expiration d'un délai de gestionnaire (dans ce cas, mon 'expirationHandler" bloquer) sera exécutée si le temps d'exécution est plus. En définissant le bloc dans un bloc de variable, on peut de manière récursive commencer le long de la tâche en cours d'exécution dans le gestionnaire d'expiration. Cela conduit dans l'infini de l'exécution, aussi.
Sachez pour terminer la tâche, si votre application passe en premier plan à nouveau. Et de mettre fin à la tâche si vous en avez le plus besoin.
Pour ma propre expérience, j'ai mesuré à quelque chose.
L'aide de l'emplacement des rappels d'avoir le GPS, la radio est en train de sucer ma batterie descend très rapidement. L'utilisation de l'approche que j'ai posté dans la mise à Jour 2 prend presque pas d'énergie. Selon le "userexperience" c'est une meilleure approche. Peut-être que d'autres Applications de ce genre, cachant son comportement derrière la fonctionnalité GPS ...