Utilisation des tâches en arrière-plan dans les applications Windows
Découvrez comment créer et inscrire une tâche en arrière-plan dans votre application avec windows Runtime (WinRT) BackgroundTaskBuilder classe.
Enregistrer une tâche en arrière-plan
Consultez l’exemple BackgroundTask pour obtenir un exemple complet d’inscription d’une tâche en arrière-plan dans une application de plateforme Windows universelle (UWP).
L’exemple suivant montre l’inscription d’une tâche COM Win32 qui s’exécute sur un minuteur périodique de 15 minutes.
Pour inscrire une tâche en arrière-plan, vous devez d’abord créer une instance de la classe BackgroundTaskBuilder. La classe BackgroundTaskBuilder
est utilisée pour créer et inscrire des tâches en arrière-plan dans votre application. L’exemple de code suivant montre comment créer une instance de la classe BackgroundTaskBuilder
:
using System;
using Windows.ApplicationModel.Background;
public IBackgroundTaskRegistration RegisterBackgroundTaskWithSystem(IBackgroundTrigger trigger, Guid entryPointClsid, string taskName)
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.SetTrigger(trigger);
builder.SetTaskEntryPointClsid(entryPointClsid);
BackgroundTaskRegistration registration;
if (builder.Validate())
{
registration = builder.Register(taskName);
}
else
{
registration = null;
}
return registration;
}
RegisterBackgroundTaskWithSystem(new TimeTrigger(15, false), typeof(TimeTriggeredTask).GUID, typeof(TimeTriggeredTask).Name);
La méthode RegisterBackgroundTaskWithSystem
prend trois paramètres :
-
trigger
: déclencheur qui démarre la tâche en arrière-plan. -
entryPointClsid
: ID de classe du point d’entrée de tâche en arrière-plan. -
taskName
: nom de la tâche en arrière-plan.
La méthode RegisterBackgroundTaskWithSystem
crée une nouvelle instance de la classe BackgroundTaskBuilder
et définit l’ID de classe de déclencheur et de point d’entrée pour la tâche en arrière-plan. La méthode inscrit ensuite la tâche en arrière-plan auprès du système.
Note
Cette classe n’est pas agile, ce qui signifie que vous devez prendre en compte son modèle de gestion des threads et son comportement de transfert de données. Pour plus d’informations, consultez Threading et Marshaling (C++/CX) et Utilisation d’objets Windows Runtime dans un environnement multithread (.NET).
Gérer la veille moderne dans une tâche en arrière-plan
Les BackgroundTaskBuilder et les API associées permettent déjà aux applications de bureau empaquetées d’exécuter des tâches en arrière-plan. L’API étend désormais ces API pour permettre à ces applications d’exécuter du code en veille moderne. La mise à jour ajoute également des propriétés qui peuvent être interrogées par une application pour déterminer si le système limite les tâches en arrière-plan de l’application en veille moderne afin d’économiser la durée de vie de la batterie. Cela permet des scénarios tels que les applications recevant des appels VoIP ou d’autres notifications push de veille moderne.
Note
« Applications de bureau packagées » dans cette section fait référence aux applications Win32 qui ont une identité de package (c’est-à-dire, sont des applications Desktop Bridge ou des applications packagées signées de type Sparse) et qui ont une fonction principale (ou wmain) comme point d’entrée.
L’exemple suivant montre comment un développeur d’applications peut utiliser l’API BackgroundTaskBuilder pour inscrire au maximum une tâche avec le nom de la tâche spécifiée. L’exemple montre également comment vérifier et choisir l’inscription des tâches à exécuter en veille moderne pour les tâches les plus critiques de l’application.
// The following namespace is required for BackgroundTaskBuilder APIs.
using Windows.ApplicationModel.Background;
// The following namespace is required for API version checks.
using Windows.Foundation.Metadata;
// The following namespace is used for showing Toast Notifications. This
// namespace requires the Microsoft.Toolkit.Uwp.Notifications NuGet package
// version 7.0 or greater.
using Microsoft.Toolkit.Uwp.Notifications;
// Incoming calls are considered to be critical tasks to the operation of the app.
const string IncomingCallTaskName = "IncomingCallTask";
const string NotificationTaskName = "NotificationTask";
const string PrefetchTaskName = "PrefetchTask";
public static bool IsAllowedInBackground(BackgroundAccessStatus status) {
return ((status != BackgroundAccessStatus.Denied) &&
(status != BackgroundAccessStatus.DeniedBySystemPolicy) &&
(status != BackgroundAccessStatus.DeniedByUser) &&
(status != BackgroundAccessStatus.Unspecified));
}
public async void RegisterTask(IBackgroundTrigger trigger,
Guid entryPointClsid,
string taskName,
bool isRunInStandbyRequested)
{
var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.SetTrigger(trigger);
taskBuilder.SetTaskEntryPointClsid(entryPointClsid);
// Only the most critical background work should be allowed to proceed in
// modern standby. Additionally, some platforms may not support modern
// or running background tasks in modern standby at all. Only attempt to
// request modern standby execution if both are true. Requesting network
// is necessary when running in modern standby to handle push notifications.
if (IsRunInStandbyRequested && taskBuilder.IsRunningTaskInStandbySupported)
{
var accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby();
if (!IsAllowedInBackground(accessStatus)
{
await BackgroundExecutionManager.RequestAccessKindForModernStandby(
BackgroundAccessRequestKind.AllowedSubjectToSystemPolicy,
"This app wants to receive incoming notifications while your device is asleep");
}
accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby();
if (IsAllowedInBackground(accessStatus)
{
taskBuilder.IsRunningTaskInStandbyRequested = true;
taskBuilder.IsNetworkRequested = true;
}
}
// Check that the registration is valid before attempting to register.
if (taskBuilder.IsRegistrationValid)
{
// If a task with the specified name already exists, it is unregistered
// before a new one is registered. Note this API may still fail from
// catastrophic failure (e.g., memory allocation failure).
taskBuilder.Register(taskName);
}
return;
}
RegisterTask(new PushNotificationTrigger(), "{INSERT-YOUR-GUID-HERE}", IncomingCallTaskName, true);
Vérifier si les tâches en arrière-plan ont dépassé leur budget en veille moderne
L’exemple de code suivant montre comment un développeur d’applications peut utiliser les BackgroundWorkCost.WasApplicationThrottledInStandby et BackgroundWorkCost.ApplicationEnergyUseLevel pour surveiller et réagir à l’épuisement du budget alloué aux tâches d'arrière-plan de son application. Le développeur d’applications peut réagir en réduisant les tâches de priorité inférieure effectuées en veille moderne. Notez que cela s’appuie sur le code de l’exemple précédent.
public async void ReduceBackgroundCost()
{
BackgroundTaskRegistration callTask;
BackgroundTaskRegistration notificationTask;
BackgroundTaskRegistration prefetchTask;
// Nothing to do if the app was not or will not be throttled.
if (!BackgroundWorkCost.WasApplicationThrottledInStandby &&
(BackgroundWorkCost.ApplicationEnergyUseLevel != StandbyEnergyUseLevel.OverBudget))
{
return;
}
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
switch (task.Value.Name) {
case IncomingCallTaskName:
callTask = task.Value;
break;
case NotificationTaskName:
notificationTask = task.Value;
break;
case PrefetchTaskName:
prefetchTask = task.Value;
break;
default:
}
}
if (callTask.WasTaskThrottledInStandby)
{
// Unset the throttle flag after acknowledging it so the app can
// react to the same task being throttled again in the future.
task.Value.WasTaskThrottledInStandby = false;
// Notify the user that the notification was missed.
new ToastContentBuilder()
.AddText("You missed a call")
.AddText(task.Value.Name)
.Show();
// Because the incoming calls were not activated, demote less notifications
// tasks so the calls can be delivered promptly in the future.
RegisterTask(notificationTask.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
notificationTask.Value.Name,
false);
}
// Note that if incoming call tasks were throttled in some previous modern
// standby session, the application energy use was over budget for some period.
// Demote unimportant tasks like prefetch work to avoid calls and notifications
// from being throttled.
if (callTask.WasTaskThrottledInStandby) ||
(BackgroundWorkCost.ApplicationEnergyUseLevel == StandbyEnergyUseLevel.OverBudget))
{
RegisterTask(prefetchTask.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
prefetchTask.Value.Name,
false);
}
return;
}
Surveiller les tendances d’utilisation de l’énergie des tâches en arrière-plan
Voici une mise à jour incrémentielle de bout en bout pour l’exemple de code C++WinRT/C# suivant sur GitHub.
L’exemple montre comment utiliser le BackgroundWorkCost.ApplicationEnergyUseTrend pour surveiller la tendance de vos tâches en arrière-plan à épuiser leur budget. Vous pouvez également empêcher l’exécution des tâches en arrière-plan les plus coûteuses en mode de secours moderne et empêcher les tâches en arrière-plan de s’exécuter en veille moderne si leur application utilise son budget trop rapidement. Cet exemple s’appuie sur du code provenant d’exemples précédents.
public async void ReduceBackgroundCostPreemptively()
{
BackgroundTaskRegistration mostExpensiveTask = null;
// We can't do anything preemptively since the trend isn't known.
if (!BackgroundWorkCost.IsApplicationEnergyUseTrendKnown)
{
return;
}
// The app is not trending towards being over budget, so this method can
// return early.
if ((BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverBudget) &&
(BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverHalf))
{
return;
}
// The application is going exceeding its budget very quickly. Demote the
// most expensive task that is not the call task before call tasks start being
// throttled.
if (BackgroundWorkCost.ApplicationEnergyUseTrend == EnergyUseTrend.OverBudget)
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if ((task.Value.Name != IncomingCallTaskName) &&
((mostExpensiveTask == null) ||
(mostExpensiveTask.ApplicationEnergyUseTrendContributionPercentage <
task.Value.ApplicationEnergyUseTrendContributionPercentage)))
{
mostExpensiveTask = task.Value;
}
}
}
if (mostExpensiveTask != null)
{
RegisterTask(mostExpensiveTask.Trigger,
typeof(TimeTriggeredTask).GUID,
mostExpensiveTask.Name,
false);
}
// The application is trending toward eventually exceeding its budget. Demote the
// least important prefetch task before calls and notifications are throttled.
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == PrefetchTaskName) {
RegisterTask(task.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
task.Value.Name,
false);
}
}
return;
}
Tâches en arrière-plan et connectivité réseau
Si votre tâche en arrière-plan nécessite une connectivité réseau, tenez compte des considérations suivantes.
Déclencheurs liés au réseau
- Utilisez un SocketActivityTrigger pour activer la tâche en arrière-plan lorsqu’un paquet est reçu et que vous devez effectuer une tâche de courte durée. Une fois la tâche terminée, la tâche en arrière-plan doit se terminer pour économiser de l’énergie.
- Utilisez un ControlChannelTrigger pour activer la tâche en arrière-plan lorsqu’un paquet est reçu et que vous devez effectuer une tâche de longue durée.
Conditions et indicateurs liés au réseau
- Ajoutez la condition InternetAvailable (BackgroundTaskBuilder.AddCondition) à votre tâche en arrière-plan pour retarder le déclenchement de la tâche en arrière-plan jusqu’à ce que la pile réseau soit en cours d’exécution. Cette condition économise de l'énergie, car la tâche d'arrière-plan ne s'exécute pas tant que l'accès réseau n'est pas disponible. Cette condition ne fournit pas d’activation en temps réel.
- Quel que soit le déclencheur que vous utilisez, définissez IsNetworkRequested sur votre tâche d'arrière-plan pour vous assurer que le réseau reste opérationnel lorsque la tâche s'exécute. Cela indique à l’infrastructure de tâche en arrière-plan de maintenir le réseau pendant l’exécution de la tâche, même si l’appareil a entré en mode veille connectée. Si votre tâche en arrière-plan n’utilise pas IsNetworkRequested, votre tâche en arrière-plan ne pourra pas accéder au réseau en mode Veille connectée.
Contenu connexe
Windows developer