Создание и регистрация внепроцессной фоновой задачиCreate and register an out-of-process background task

Важные APIImportant APIs

Создайте класс фоновой задачи и зарегистрируйте его выполнение, когда приложение не работает на переднем плане.Create a background task class and register it to run when your app is not in the foreground. В этом разделе рассказывается, как создать и зарегистрировать фоновую задачу, которая будет запускаться в отдельном процессе, а не в процессе вашего приложения.This topic demonstrates how to create and register a background task that runs in a separate process than your app's process. Руководство по реализации выполнения фоновой задачи непосредственно в приложении переднего плана см. в разделе Создание и регистрация фоновой задачи, выполняемой внутри процесса.To do background work directly in the foreground application, see Create and register an in-process background task.

Примечание

Если фоновая задача используется для воспроизведения мультимедиа в фоновом режиме, см. раздел Воспроизведение мультимедиа в фоновом режиме, где приведены сведения об улучшениях в Windows 10 версии 1607, которые значительно упрощают работу.If you use a background task to play media in the background, see Play media in the background for information about improvements in Windows 10, version 1607, that make it much easier.

Создание класса фоновой задачиCreate the Background Task class

Для выполнения кода в фоновом режиме можно создавать классы, в которых реализован интерфейс IBackgroundTask.You can run code in the background by writing classes that implement the IBackgroundTask interface. Этот код выполняется при запуске определенного события с помощью, например, системтригжер или маинтенанцетригжер.This code runs when a specific event is triggered by using, for example, SystemTrigger or MaintenanceTrigger.

Далее будет показано, как создать новый класс, реализующий интерфейс IBackgroundTask.The following steps show you how to write a new class that implements the IBackgroundTask interface.

  1. Создайте новый проект для фоновых задач и добавьте его в решение.Create a new project for background tasks and add it to your solution. Для этого щелкните правой кнопкой мыши узел решения в Обозреватель решений и выберите Добавить > Новый проект.To do this, right-click on your solution node in the Solution Explorer and select Add > New Project. Затем выберите тип проекта компонент Среда выполнения Windows , присвойте проекту имя и нажмите кнопку ОК.Then select the Windows Runtime Component project type, name the project, and click OK.
  2. Создайте ссылку на проект фоновых задач в проекте приложения UWP.Reference the background tasks project from your Universal Windows Platform (UWP) app project. Для приложения C# или C++ в проекте приложения щелкните правой кнопкой мыши ссылки и выберите команду Добавить новую ссылку.For a C# or C++ app, in your app project, right-click on References and select Add New Reference. В разделе Решение выберите Проекты, затем выберите имя своего проекта фоновых задач и нажмите ОК.Under Solution, select Projects and then select the name of your background task project and click Ok.
  3. В проект фоновые задачи добавьте новый класс, реализующий интерфейс IBackgroundTask .To the background tasks project, add a new class that implements the IBackgroundTask interface. Метод IBackgroundTask. Run является обязательной точкой входа, которая будет вызываться при активации указанного события. Этот метод является обязательным в каждой фоновой задаче.The IBackgroundTask.Run method is a required entry point that will be called when the specified event is triggered; this method is required in every background task.

Примечание

Класс фоновой задачи — и все остальные классы в проекте фоновой задачи — должны быть общедоступными классами, которые являются запечатанными (или окончательными).The background task class itself—and all other classes in the background task project—need to be public classes that are sealed (or final).

В следующем образце кода показана самая простая начальная точка для класса фоновой задачи.The following sample code shows a very basic starting point for a background task class.

// 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. Если в вашей фоновой задаче выполняется асинхронный код, для нее необходимо использовать задержку.If you run any asynchronous code in your background task, then your background task needs to use a deferral. Если вы не используете РБП, процесс фоновой задачи может неожиданно завершиться, если метод Run возвращает значение до завершения выполнения любой асинхронной работы.If you don't use a deferral, then the background task process can terminate unexpectedly if the Run method returns before any asynchronous work has run to completion.

Запросите РБП в методе Run перед вызовом асинхронного метода.Request the deferral in the Run method before calling the asynchronous method. Сохраните РБП в члене данных класса, чтобы к нему можно было получить доступ из асинхронного метода.Save the deferral to a class data member so that it can be accessed from the asynchronous method. Объявите задержку завершенной после выполнения асинхронного кода.Declare the deferral complete after the asynchronous code completes.

Следующий пример кода получает РБП, сохраняет его и освобождает после завершения асинхронного кода.The following sample code gets the deferral, saves it, and releases it when the asynchronous code is complete.

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();
    });
}

Примечание

В C# асинхронные методы вашей фоновой задачи можно вызвать с помощью ключевых слов async/await.In C#, your background task's asynchronous methods can be called using the async/await keywords. В C++/CX аналогичный результат можно достичь с помощью цепочки задач.In C++/CX, a similar result can be achieved by using a task chain.

Подробнее о шаблонах асинхронных операций см. в разделе Асинхронное программирование.For more information about asynchronous patterns, see Asynchronous programming. Дополнительные примеры использования задержек для предотвращения преждевременной остановки фоновой задачи см. в примере фоновой задачи.For additional examples of how to use deferrals to keep a background task from stopping early, see the background task sample.

Следующие действия выполняются в одном из классов вашего приложения (например, MainPage.xaml.cs).The following steps are completed in one of your app classes (for example, MainPage.xaml.cs).

Примечание

Вы также можете создать функцию, предназначенную для регистрации фоновых задач — . см. раздел Регистрация фоновой задачи.You can also create a function dedicated to registering background tasks—see Register a background task. В этом случае вместо выполнения следующих трех шагов можно просто создать триггер и предоставить его функции регистрации вместе с именем задачи, точкой входа задачи и (необязательно) условием.In that case, instead of using the next three steps, you can simply construct the trigger and provide it to the registration function along with the task name, task entry point, and (optionally) a condition.

Регистрация фоновой задачи для запускаRegister the background task to run

  1. Определите, зарегистрирована ли фоновая задача путем прохода по свойству баккграундтаскрегистратион. аллтаскс .Find out whether the background task is already registered by iterating through the BackgroundTaskRegistration.AllTasks property. Это важный шаг: если приложение не проверяет, зарегистрирована ли уже фоновая задача, оно может выполнить регистрацию несколько раз, вызывая проблемы производительности и полное использование доступного задаче времени ЦП до завершения работы.This step is important; if your app doesn't check for existing background task registrations, it could easily register the task multiple times, causing issues with performance and maxing out the task's available CPU time before work can complete.

В следующем примере выполняется итерация свойства аллтаскс и устанавливается значение true для переменной флага, если задача уже зарегистрирована.The following example iterates on the AllTasks property and sets a flag variable to true if the task is already registered.

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. Если фоновая задача еще не зарегистрирована, используйте BackgroundTaskBuilder для создания экземпляра фоновой задачи.If the background task is not already registered, use BackgroundTaskBuilder to create an instance of your background task. Точка входа задачи является именем класса фоновых задач, перед которым располагается пространство имен.The task entry point should be the name of your background task class prefixed by the namespace.

Триггер фоновой задачи определяет, когда должна быть запущена фоновая задача.The background task trigger controls when the background task will run. Список возможных триггеров см. в статье SystemTrigger.For a list of possible triggers, see SystemTrigger.

Например, этот код создает новую фоновую задачу и задает ее выполнение при наступлении триггера тимезонечанжед :For example, this code creates a new background task and sets it to run when the TimeZoneChanged trigger occurs:

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. Вы можете добавить условие, чтобы контролировать, в какой момент времени после возникновения события триггера запустится ваша задача (не обязательно).You can add a condition to control when your task will run after the trigger event occurs (optional). Например, если вы не хотите, чтобы задача запускалась в отсутствие пользователя, используйте условие UserPresent.For example, if you don't want the task to run until the user is present, use the condition UserPresent. Список возможных условий см. в статье SystemConditionType.For a list of possible conditions, see SystemConditionType.

Следующий пример кода назначает условие, при котором необходимо присутствие пользователя:The following sample code assigns a condition requiring the user to be present:

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. Зарегистрируйте фоновую задачу, вызвав метод Register в объекте **BackgroundTaskBuilder **.Register the background task by calling the Register method on the BackgroundTaskBuilder object. Сохраните результат выполнения BackgroundTaskRegistration, чтобы использовать его в следующем шаге.Store the BackgroundTaskRegistration result so it can be used in the next step.

Следующий код регистрирует фоновую задачу и сохраняет результат.The following code registers the background task and stores the result:

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

Примечание

Универсальные приложения для Windows должны вызвать RequestAccessAsync перед регистрацией любых типов фоновых триггеров.Universal Windows apps must call RequestAccessAsync before registering any of the background trigger types.

Чтобы универсальное приложение для Windows продолжало корректно работать после выпуска обновления, необходимо использовать триггер ServicingComplete (см. раздел SystemTriggerType), чтобы внести любые изменения в конфигурацию после обновления, такие как перенос базы данных приложения и регистрация фоновых задач.To ensure that your Universal Windows app continues to run properly after you release an update, use the ServicingComplete (see SystemTriggerType) trigger to perform any post-update configuration changes such as migrating the app's database and registering background tasks. В настоящий момент рекомендуется отменить регистрацию фоновых задач, связанных с предыдущей версией приложения (см. раздел RemoveAccess), и регистрировать фоновые задачи для новой версии приложения (см. раздел RequestAccessAsync).It is best practice to unregister background tasks associated with the previous version of the app (see RemoveAccess) and register background tasks for the new version of the app (see RequestAccessAsync) at this time.

Дополнительные сведения см. в разделе Руководство по фоновым задачам.For more information, see Guidelines for background tasks.

Обработка завершения фоновой задачи с помощью обработчиков событийHandle background task completion using event handlers

Следует зарегистрировать метод с помощью BackgroundTaskCompletedEventHandler, чтобы ваше приложение могло получить результаты от фоновой задачи.You should register a method with the BackgroundTaskCompletedEventHandler, so that your app can get results from the background task. При запуске или возобновлении работы приложения помеченный метод будет вызываться, если фоновая задача была завершена с момента последнего времени, когда приложение находилось на переднем плане.When the app is launched or resumed, the marked method will be called if the background task has completed since the last time the app was in the foreground. (Метод OnCompleted будет вызван немедленно, если фоновая задача завершается во время работы приложения на переднем плане в настоящее время.)(The OnCompleted method will be called immediately if the background task completes while your app is currently in the foreground.)

  1. Создайте метод OnCompleted для обработки завершения фоновых задач.Write an OnCompleted method to handle the completion of background tasks. Например, результат фоновой задачи может быть причиной обновления пользовательского интерфейса.For example, the background task result might cause a UI update. Представленный здесь объем памяти метода необходим для метода обработчика событий OnCompleted, даже если в этом примере не используется параметр args.The method footprint shown here is required for the OnCompleted event handler method, even though this example does not use the args parameter.

Следующий пример кода распознает завершение фоновой задачи и вызывает пример метода (принимающего строку сообщения) для обновления пользовательского интерфейса.The following sample code recognizes background task completion and calls an example UI update method that takes a message string.

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);
}

Примечание

Обновления пользовательского интерфейса должны выполняться асинхронно, чтобы избежать остановки потока пользовательского интерфейса.UI updates should be performed asynchronously, to avoid holding up the UI thread. Пример см. в методе UpdateUI в образце фоновой задачи.For an example, see the UpdateUI method in the background task sample.

  1. Вернитесь к тому месту, где вы регистрировали фоновую задачу.Go back to where you registered the background task. После этой строки кода добавьте новый объект BackgroundTaskCompletedEventHandler.After that line of code, add a new BackgroundTaskCompletedEventHandler object. Предоставьте свой метод OnCompleted в качестве параметра для конструктора BackgroundTaskCompletedEventHandler.Provide your OnCompleted method as the parameter for the BackgroundTaskCompletedEventHandler constructor.

Следующий пример кода добавляет BackgroundTaskCompletedEventHandler в BackgroundTaskRegistration.The following sample code adds a BackgroundTaskCompletedEventHandler to the BackgroundTaskRegistration:

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

Объявите в манифесте приложения, что приложение использует фоновые задачиDeclare in the app manifest that your app uses background tasks

Чтобы приложение могло выполнять фоновые задачи, вам необходимо сперва объявить каждую такую задачу в манифесте приложения.Before your app can run background tasks, you must declare each background task in the app manifest. Если приложение пытается зарегистрировать фоновую задачу с триггером, который не указан в манифесте, регистрация фоновой задачи завершится ошибкой с ошибкой "класс среды выполнения не зарегистрирован".If your app attempts to register a background task with a trigger that isn't listed in the manifest, the registration of the background task will fail with a "runtime class not registered" error.

  1. Откройте конструктор манифеста пакета, запустив файл Package.appxmanifest.Open the package manifest designer by opening the file named Package.appxmanifest.
  2. Перейдите на вкладку Объявления.Open the Declarations tab.
  3. В раскрывающемся списке Доступные объявления выберите Фоновые задачи и щелкните Добавить.From the Available Declarations drop-down, select Background Tasks and click Add.
  4. Установите флажок Системное событие.Select the System event checkbox.
  5. В текстовом поле точка входа: введите пространство имен и имя класса фонового рисунка, например Tasks. ексамплебаккграундтаск.In the Entry point: textbox, enter the namespace and name of your background class which is for this example is Tasks.ExampleBackgroundTask.
  6. Закройте конструктор манифестов.Close the manfiest designer.

Следующий элемент расширений добавляется в файл Package.appxmanifest для регистрации фоновой задачи:The following Extensions element is added to your Package.appxmanifest file to register the background task:

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

Сводка и дальнейшие действияSummary and next steps

Теперь вы понимаете, как создавать класс фоновой задачи, как регистрировать фоновую задачу из приложения и как сделать так, чтобы приложение распознавало ее завершение.You should now understand the basics of how to write a background task class, how to register the background task from within your app, and how to make your app recognize when the background task is complete. Вы также знаете, как обновить манифест приложения, чтобы приложение могло успешно регистрировать фоновые задачи.You should also understand how to update the application manifest so that your app can successfully register the background task.

Примечание

Скачайте пример фоновой задачи, чтобы увидеть похожие примеры кода в контексте полного и надежного приложения UWP, использующего фоновые задачи.Download the background task sample to see similar code examples in the context of a complete and robust UWP app that uses background tasks.

В статьях ниже можно найти справочник по API, концептуальное руководство по фоновым задачам и подробные инструкции по созданию приложений, использующих фоновые задачи.See the following related topics for API reference, background task conceptual guidance, and more detailed instructions for writing apps that use background tasks.

Учебные статьи с подробными сведениями о фоновых задачахDetailed background task instructional topics

Руководство по фоновым задачамBackground task guidance

Справочник по API для фоновых задачBackground Task API Reference