Compartir a través de


Crear y registrar una tarea en segundo plano fuera del proceso

API importantes

Cree una clase de tarea en segundo plano y regístrela para que se ejecute cuando la aplicación no esté en primer plano. En este tema se muestra cómo crear y registrar una tarea en segundo plano que se ejecuta en un proceso independiente que el proceso de la aplicación. Para realizar trabajos en segundo plano directamente en la aplicación en primer plano, consulte Creación y registro de una tarea en segundo plano en proceso.

Nota:

Si usas una tarea en segundo plano para reproducir elementos multimedia en segundo plano, consulta Reproducir contenido multimedia en segundo plano para obtener información sobre las mejoras en Windows 10, versión 1607, que facilitan mucho.

Nota:

Si va a implementar una tarea en segundo plano fuera del proceso en una aplicación de escritorio de C# con .NET 6 o posterior, use la compatibilidad con la creación de C#/WinRT para crear un componente de Windows Runtime. Esto se aplica a las aplicaciones que usan el SDK de Aplicaciones para Windows, WinUI 3, WPF o WinForms. Consulte el ejemplo de tarea En segundo plano para obtener un ejemplo.

Crear la clase Tarea en segundo plano

Puede ejecutar código en segundo plano escribiendo clases que implementan la interfaz IBackgroundTask. Este código se ejecuta cuando se desencadena un evento específico mediante, por ejemplo, SystemTrigger o MaintenanceTrigger.

Los pasos siguientes muestran cómo escribir una nueva clase que implemente la interfaz IBackgroundTask.

  1. Cree un nuevo proyecto para tareas en segundo plano y agréguelo a la solución. Para ello, haga clic con el botón derecho en el nodo de la solución en el Explorador de soluciones y seleccione Agregar>nuevo proyecto. A continuación, seleccione el tipo de proyecto Componente de Windows Runtime, asigne un nombre al proyecto y haga clic en Aceptar.
  2. Haga referencia al proyecto de tareas en segundo plano desde el proyecto de aplicación de Plataforma universal de Windows (UWP). Para una aplicación de C# o C++, en el proyecto de aplicación, haga clic con el botón derecho en Referencias y seleccione Agregar nueva referencia. En Solución, seleccione Proyectos y, a continuación, seleccione el nombre del proyecto de tarea en segundo plano y haga clic en Aceptar.
  3. En el proyecto de tareas en segundo plano, agregue una nueva clase que implemente la interfaz IBackgroundTask. El método IBackgroundTask.Run es un punto de entrada necesario al que se llamará cuando se desencadene el evento especificado; este método es necesario en cada tarea en segundo plano.

Nota:

La propia clase de tarea en segundo plano (y todas las demás clases del proyecto de tarea en segundo plano) deben ser clases públicas selladas (o finales).

El código de ejemplo siguiente muestra un punto de partida muy básico para una clase de tarea en segundo plano.

// ExampleBackgroundTask.cs
using Windows.ApplicationModel.Background;

namespace Tasks
{
    public sealed class ExampleBackgroundTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            
        }        
    }
}
// First, add ExampleBackgroundTask.idl, and then build.
// ExampleBackgroundTask.idl
namespace Tasks
{
    [default_interface]
    runtimeclass ExampleBackgroundTask : Windows.ApplicationModel.Background.IBackgroundTask
    {
        ExampleBackgroundTask();
    }
}

// ExampleBackgroundTask.h
#pragma once

#include "ExampleBackgroundTask.g.h"

namespace winrt::Tasks::implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask>
    {
        ExampleBackgroundTask() = default;

        void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance);
    };
}

namespace winrt::Tasks::factory_implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask, implementation::ExampleBackgroundTask>
    {
    };
}

// ExampleBackgroundTask.cpp
#include "pch.h"
#include "ExampleBackgroundTask.h"

namespace winrt::Tasks::implementation
{
    void ExampleBackgroundTask::Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
    {
        throw hresult_not_implemented();
    }
}
// ExampleBackgroundTask.h
#pragma once

using namespace Windows::ApplicationModel::Background;

namespace Tasks
{
    public ref class ExampleBackgroundTask sealed : public IBackgroundTask
    {

    public:
        ExampleBackgroundTask();

        virtual void Run(IBackgroundTaskInstance^ taskInstance);
        void OnCompleted(
            BackgroundTaskRegistration^ task,
            BackgroundTaskCompletedEventArgs^ args
        );
    };
}

// ExampleBackgroundTask.cpp
#include "ExampleBackgroundTask.h"

using namespace Tasks;

void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
}
  1. Si ejecuta algún código asincrónico en la tarea en segundo plano, la tarea en segundo plano debe usar un aplazamiento. Si no usa un aplazamiento, el proceso de tarea en segundo plano puede finalizar inesperadamente si el método Run devuelve antes de que se haya ejecutado un trabajo asincrónico hasta su finalización.

Solicite el aplazamiento en el método Run antes de llamar al método asincrónico. Guarde el aplazamiento en un miembro de datos de clase para que se pueda acceder desde el método asincrónico. Declare el aplazamiento completado una vez completado el código asincrónico.

El código de ejemplo siguiente obtiene el aplazamiento, lo guarda y lo libera cuando se completa el código asincrónico.

BackgroundTaskDeferral _deferral; // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation
public async void Run(IBackgroundTaskInstance taskInstance)
{
    _deferral = taskInstance.GetDeferral();
    //
    // TODO: Insert code to start one or more asynchronous methods using the
    //       await keyword, for example:
    //
    // await ExampleMethodAsync();
    //

    _deferral.Complete();
}
// ExampleBackgroundTask.h
...
private:
    Windows::ApplicationModel::Background::BackgroundTaskDeferral m_deferral{ nullptr };

// ExampleBackgroundTask.cpp
...
Windows::Foundation::IAsyncAction ExampleBackgroundTask::Run(
    Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
{
    m_deferral = taskInstance.GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.
    // TODO: Modify the following line of code to call a real async function.
    co_await ExampleCoroutineAsync(); // Run returns at this point, and resumes when ExampleCoroutineAsync completes.
    m_deferral.Complete();
}
void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
    m_deferral = taskInstance->GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.

    //
    // TODO: Modify the following line of code to call a real async function.
    //       Note that the task<void> return type applies only to async
    //       actions. If you need to call an async operation instead, replace
    //       task<void> with the correct return type.
    //
    task<void> myTask(ExampleFunctionAsync());

    myTask.then([=]() {
        m_deferral->Complete();
    });
}

Nota:

En C#, se puede llamar a los métodos asincrónicos de la tarea en segundo plano mediante las palabras clave async/await . En C++/CX, se puede lograr un resultado similar mediante una cadena de tareas.

Para obtener más información sobre los patrones asincrónicos, consulte Programación asincrónica. Para obtener ejemplos adicionales sobre cómo usar aplazamientos para evitar que una tarea en segundo plano se detenga temprano, consulte el ejemplo de tarea en segundo plano.

Los pasos siguientes se completan en una de las clases de aplicación (por ejemplo, MainPage.xaml.cs).

Nota:

También puede crear una función dedicada al registro de tareas en segundo plano; consulte Registro de una tarea en segundo plano. En ese caso, en lugar de usar los tres pasos siguientes, simplemente puede construir el desencadenador y proporcionarlo a la función de registro junto con el nombre de la tarea, el punto de entrada de la tarea y (opcionalmente) una condición.

Registrar la tarea en segundo plano para ejecutar

  1. Averigüe si la tarea en segundo plano ya está registrada iterando a través de la propiedad BackgroundTaskRegistration.AllTasks. Este paso es importante; Si la aplicación no comprueba los registros de tareas en segundo plano existentes, podría registrar fácilmente la tarea varias veces, lo que provoca problemas con el rendimiento y el máximo del tiempo de CPU disponible de la tarea antes de que se pueda completar el trabajo.

En el ejemplo siguiente se itera en la propiedad AllTasks y se establece una variable de marca en true si la tarea ya está registrada.

var taskRegistered = false;
var exampleTaskName = "ExampleBackgroundTask";

foreach (var task in BackgroundTaskRegistration.AllTasks)
{
    if (task.Value.Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}
std::wstring exampleTaskName{ L"ExampleBackgroundTask" };

auto allTasks{ Windows::ApplicationModel::Background::BackgroundTaskRegistration::AllTasks() };

bool taskRegistered{ false };
for (auto const& task : allTasks)
{
    if (task.Value().Name() == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}

// The code in the next step goes here.
boolean taskRegistered = false;
Platform::String^ exampleTaskName = "ExampleBackgroundTask";

auto iter = BackgroundTaskRegistration::AllTasks->First();
auto hascur = iter->HasCurrent;

while (hascur)
{
    auto cur = iter->Current->Value;

    if(cur->Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }

    hascur = iter->MoveNext();
}
  1. Si la tarea en segundo plano aún no está registrada, use BackgroundTaskBuilder para crear una instancia de la tarea en segundo plano. El punto de entrada de la tarea debe ser el nombre de la clase de tarea en segundo plano prefijo por el espacio de nombres .

El desencadenador de tareas en segundo plano controla cuándo se ejecutará la tarea en segundo plano. Para obtener una lista de posibles desencadenadores, consulte SystemTrigger.

Por ejemplo, este código crea una nueva tarea en segundo plano y la establece para ejecutarse cuando se produce el desencadenador TimeZoneChanged :

var builder = new BackgroundTaskBuilder();

builder.Name = exampleTaskName;
builder.TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false));
if (!taskRegistered)
{
    Windows::ApplicationModel::Background::BackgroundTaskBuilder builder;
    builder.Name(exampleTaskName);
    builder.TaskEntryPoint(L"Tasks.ExampleBackgroundTask");
    builder.SetTrigger(Windows::ApplicationModel::Background::SystemTrigger{
        Windows::ApplicationModel::Background::SystemTriggerType::TimeZoneChange, false });
    // The code in the next step goes here.
}
auto builder = ref new BackgroundTaskBuilder();

builder->Name = exampleTaskName;
builder->TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder->SetTrigger(ref new SystemTrigger(SystemTriggerType::TimeZoneChange, false));
  1. Puede agregar una condición para controlar cuándo se ejecutará la tarea después de que se produzca el evento desencadenador (opcional). Por ejemplo, si no desea que la tarea se ejecute hasta que el usuario esté presente, use la condición UserPresent. Para obtener una lista de las posibles condiciones, consulte SystemConditionType.

El código de ejemplo siguiente asigna una condición que requiere que el usuario esté presente:

builder.AddCondition(new SystemCondition(SystemConditionType.UserPresent));
builder.AddCondition(Windows::ApplicationModel::Background::SystemCondition{ Windows::ApplicationModel::Background::SystemConditionType::UserPresent });
// The code in the next step goes here.
builder->AddCondition(ref new SystemCondition(SystemConditionType::UserPresent));
  1. Registre la tarea en segundo plano llamando al método Register en el objeto BackgroundTaskBuilder. Almacene el resultado BackgroundTaskRegistration para que se pueda usar en el paso siguiente.

El código siguiente registra la tarea en segundo plano y almacena el resultado:

BackgroundTaskRegistration task = builder.Register();
Windows::ApplicationModel::Background::BackgroundTaskRegistration task{ builder.Register() };
BackgroundTaskRegistration^ task = builder->Register();

Nota:

Las aplicaciones universales de Windows deben llamar a RequestAccessAsync antes de registrar cualquiera de los tipos de desencadenador en segundo plano.

Para asegurarse de que la aplicación universal de Windows sigue ejecutándose correctamente después de publicar una actualización, use el desencadenador ServicingComplete (consulte SystemTriggerType) para realizar cualquier cambio de configuración posterior a la actualización, como migrar la base de datos de la aplicación y registrar tareas en segundo plano. Es recomendable anular el registro de las tareas en segundo plano asociadas a la versión anterior de la aplicación (consulte RemoveAccess) y registrar tareas en segundo plano para la nueva versión de la aplicación (consulte RequestAccessAsync) en este momento.

Para obtener más información, vea Directrices para tareas en segundo plano.

Controlar la finalización de tareas en segundo plano mediante controladores de eventos

Debes registrar un método con BackgroundTaskCompletedEventHandler para que la aplicación pueda obtener resultados de la tarea en segundo plano. Cuando se inicia o reanuda la aplicación, se llamará al método marcado si la tarea en segundo plano se ha completado desde la última vez que la aplicación estaba en primer plano. (Se llamará inmediatamente al método OnCompleted si la tarea en segundo plano se completa mientras la aplicación está en primer plano).

  1. Escriba un método OnCompleted para controlar la finalización de tareas en segundo plano. Por ejemplo, el resultado de la tarea en segundo plano podría provocar una actualización de la interfaz de usuario. La superficie del método que se muestra aquí es necesaria para el método del controlador de eventos OnCompleted, aunque en este ejemplo no se usa el parámetro args .

El código de ejemplo siguiente reconoce la finalización de tareas en segundo plano y llama a un método de actualización de interfaz de usuario de ejemplo que toma una cadena de mensaje.

private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
    var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
    var key = task.TaskId.ToString();
    var message = settings.Values[key].ToString();
    UpdateUI(message);
}
void UpdateUI(winrt::hstring const& message)
{
    MyTextBlock().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [=]()
    {
        MyTextBlock().Text(message);
    });
}

void OnCompleted(
    Windows::ApplicationModel::Background::BackgroundTaskRegistration const& sender,
    Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs const& /* args */)
{
	// You'll previously have inserted this key into local settings.
    auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings().Values() };
    auto key{ winrt::to_hstring(sender.TaskId()) };
    auto message{ winrt::unbox_value<winrt::hstring>(settings.Lookup(key)) };

    UpdateUI(message);
}
void MainPage::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
{
    auto settings = ApplicationData::Current->LocalSettings->Values;
    auto key = task->TaskId.ToString();
    auto message = dynamic_cast<String^>(settings->Lookup(key));
    UpdateUI(message);
}

Nota:

Las actualizaciones de la interfaz de usuario deben realizarse de forma asincrónica para evitar mantener el subproceso de la interfaz de usuario. Para obtener un ejemplo, vea el método UpdateUI en el ejemplo de tarea en segundo plano.

  1. Vuelva a donde registró la tarea en segundo plano. Después de esa línea de código, agregue un nuevo objeto BackgroundTaskCompletedEventHandler. Proporcione el método OnCompleted como parámetro para el constructor BackgroundTaskCompletedEventHandler .

El código de ejemplo siguiente agrega un backgroundTaskCompletedEventHandler a BackgroundTaskRegistration:

task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
task.Completed({ this, &MainPage::OnCompleted });
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &MainPage::OnCompleted);

Declarar en el manifiesto de aplicación que la aplicación usa tareas en segundo plano

Para que la aplicación pueda ejecutar tareas en segundo plano, debes declarar cada tarea en segundo plano en el manifiesto de la aplicación. Si la aplicación intenta registrar una tarea en segundo plano con un desencadenador que no aparece en el manifiesto, el registro de la tarea en segundo plano producirá un error de "clase en tiempo de ejecución no registrado".

  1. Abra el diseñador de manifiestos del paquete abriendo el archivo denominado Package.appxmanifest.
  2. Abra la pestaña Declaraciones .
  3. En la lista desplegable Declaraciones disponibles, seleccione Tareas en segundo plano y haga clic en Agregar.
  4. Active la casilla Evento del sistema .
  5. En el cuadro de texto Punto de entrada: , escriba el espacio de nombres y el nombre de la clase en segundo plano, que es para este ejemplo Tasks.ExampleBackgroundTask.
  6. Cierre el diseñador de manifiestos.

El siguiente elemento Extensions se agrega al archivo Package.appxmanifest para registrar la tarea en segundo plano:

<Extensions>
  <Extension Category="windows.backgroundTasks" EntryPoint="Tasks.ExampleBackgroundTask">
    <BackgroundTasks>
      <Task Type="systemEvent" />
    </BackgroundTasks>
  </Extension>
</Extensions>

Resumen y pasos siguientes

Ahora debería comprender los conceptos básicos de cómo escribir una clase de tarea en segundo plano, cómo registrar la tarea en segundo plano desde dentro de la aplicación y cómo hacer que la aplicación reconozca cuando se complete la tarea en segundo plano. También debe comprender cómo actualizar el manifiesto de aplicación para que la aplicación pueda registrar correctamente la tarea en segundo plano.

Nota:

Descargue el ejemplo de tarea en segundo plano para ver ejemplos de código similares en el contexto de una aplicación para UWP completa y sólida que usa tareas en segundo plano.

Consulte los siguientes temas relacionados para la referencia de API, instrucciones conceptuales de tareas en segundo plano y instrucciones más detalladas para escribir aplicaciones que usan tareas en segundo plano.

Temas informativos detallados sobre tareas en segundo plano

Guía de tareas en segundo plano

Referencia de API de tareas en segundo plano