Out-of-process 백그라운드 작업 만들기 및 등록

중요 API

백그라운드 작업 클래스를 생성하고, 앱이 포그라운드에 없을 때 실행되도록 등록하세요. 이 토픽에서는 앱의 프로세스와 별개인 프로세스로 실행되는 백그라운드 작업을 생성하고 등록하는 방법을 보여줍니다. 포그라운드 애플리케이션에서 직접 백그라운드 작업을 수행하려면 In-process 백그라운드 작업 생성 및 등록을 참조하세요.

참고 항목

백그라운드 작업을 사용하여 백그라운드에서 미디어를 재생하는 경우, 미디어 재생이 더욱 쉬워진 Windows 10 버전 1607의 향상된 기능에 대한 자세한 내용은 백그라운드에서 미디어 재생하기를 참조하세요.

참고 항목

.NET 6 이상을 사용하여 C# 데스크톱 애플리케이션에서 Out-of-process 백그라운드 작업을 구현하려는 경우, C#/WinRT 작성 지원을 사용하여 Windows 런타임 구성 요소를 생성하세요. 이는 Windows 앱 SDK, WinUI 3, WPF 또는 WinForms를 사용하는 앱에 적용됩니다. 예제는 백그라운드 작업 샘플을 참조하세요.

백그라운드 작업 클래스 생성하기

IBackgroundTask 인터페이스를 구현하는 클래스를 작성하면 백그라운드에서 코드를 실행할 수 있습니다. 이 코드는 예를 들면, SystemTrigger 또는 MaintenanceTrigger를 사용하여 특정 이벤트가 발생할 때 실행됩니다.

다음 단계에서는 IBackgroundTask 인터페이스를 구현할 새 클래스를 작성하는 방법을 보여줍니다.

  1. 백그라운드 작업에 대한 새 프로젝트를 생성하여 원하는 솔루션에 추가하세요. 이렇게 하려면 솔루션 탐색기에서 솔루션 노드를 마우스 오른쪽 단추로 클릭하고 추가>새 프로젝트를 선택합니다. 그런 다음, Windows 런타임 구성 요소 프로젝트 형식을 선택하고, 프로젝트 이름을 지정한 후, 확인을 클릭합니다.
  2. UWP(유니버설 Windows 플랫폼) 앱 프로젝트의 백그라운드 작업 프로젝트를 참조하세요. C# 또는 C++ 앱의 경우 앱 프로젝트에서 참조 를 마우스 오른쪽 단추로 클릭하고 새 참조 추가를 선택합니다. 솔루션에서 프로젝트를 선택한 다음, 백그라운드 작업 프로젝트의 이름을 선택하고 확인을 클릭하세요.
  3. 백그라운드 작업 프로젝트에 IBackgroundTask 인터페이스를 구현하는 새 클래스를 만듭니다. IBackgroundTask.Run 메서드는 지정한 이벤트가 트리거될 때 호출되는 필수 진입점입니다. 이 메서드는 모든 백그라운드 작업에 필요합니다.

참고 항목

백그라운드 작업 클래스 자체와 백그라운드 작업 프로젝트의 다른 모든 클래스가 봉인된 또는 최종퍼블릭 클래스여야 합니다.

다음 샘플 코드는 백그라운드 작업 클래스의 기본 시작 지점을 보여 줍니다.

// 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. 백그라운드 작업에서 비동기 코드를 실행할 경우, 백그라운드 작업은 지연을 사용해야 합니다. deferral을 사용하지 않을 경우 비동기 작업이 완료되기 전에 실행 메서드가 반환하면 백그라운드 작업 프로세스가 예기치 않게 종료될 수 있습니다.

비동기 메서드를 호출하기 전에 실행 메서드에서 deferral을 요청합니다. 비동기 메서드에서 액세스할 수 있도록 deferral을 클래스 데이터 멤버에 저장합니다. 비동기 코드가 완료된 후에 지연 완료를 선언하세요.

다음 샘플 코드는 deferral을 가져와서 저장하고, 비동기 코드가 완료되면 해제합니다.

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 키워드를 사용해서 백그라운드 작업의 비동기 메서드를 호출할 수 있습니다. C++/CX에서는 작업 체인을 사용하여 유사한 결과를 얻을 수 있습니다.

비동기 패턴에 대한 자세한 내용은 비동기 프로그래밍을 참조하세요. 백그라운드 작업이 일찍 중지되지 않도록 지연을 사용하는 방법에 대한 추가 예제는 백그라운드 작업 샘플을 참조하세요.

다음 단계는 앱 클래스(예: MainPage.xaml.cs) 중 하나에서 완료됩니다.

참고 항목

백그라운드 작업을 등록하는 데에만 사용되는 함수를 만들 수도 있습니다. 백그라운드 작업 등록을 참조하세요. 이 경우 다음 세 단계를 사용하지 않고 트리거를 생성하여 작업 이름, 작업 진입점, 조건(옵션)과 함께 등록 함수에 제공하면 됩니다.

실행할 백그라운드 작업 등록하기

  1. BackgroundTaskRegistration.AllTasks 속성을 반복하여 백그라운드 작업이 이미 등록되어 있는지 확인합니다. 이 단계는 중요합니다. 앱이 기존 백그라운드 작업 등록을 확인하지 않는 경우 작업을 여러 번 등록하기 쉬우므로 성능에 문제가 발생하거나 작업이 완료되기 전에 작업의 가용 CPU 시간을 모두 사용할 수 있습니다.

다음 예제에서는 AllTasks 속성을 반복하고 작업이 이미 등록된 경우 플래그 변수를 true로 설정합니다.

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를 사용하여 백그라운드 작업의 인스턴스를 생성하세요. 작업 진입점은 네임스페이스가 접두사로 지정한 백그라운드 작업 클래스의 이름이어야 합니다.

백그라운드 작업 트리거는 백그라운드 작업이 실행되는 시기를 조절합니다. 사용 가능한 트리거의 목록은 SystemTrigger를 참조하세요.

예를 들어 이 코드는 새 백그라운드 작업을 만들고 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. 트리거 이벤트가 발생한 후에는 작업이 실행되는 시기를 조절하기 위해 조건을 추가할 수 있습니다(선택 사항). 그 예로 사용자가 존재하게 될 때까지 작업을 실행하지 않으려면 UserPresent 조건을 사용하세요. 가능한 조건의 목록은 SystemConditionType을 참조하세요.

다음 샘플 코드는 사용자가 현장에 있도록 요구하는 조건을 할당합니다.

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. BackgroundTaskBuilder 개체에서 Register(등록) 메서드를 호출해서 백그라운드 작업을 등록하세요. 다음 단계에서 사용할 수 있도록 BackgroundTaskRegistration 결과를 저장하세요.

다음 코드는 백그라운드 작업을 등록하고 그 결과를 저장합니다.

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

참고 항목

유니버설 Windows 앱은 백그라운드 트리거 유형을 어떤 것이든 등록하기 전에 RequestAccessAsync를 호출해야 합니다.

업데이트를 배포한 후에도 유니버설 Windows 앱이 계속 제대로 실행되게 하려면 ServicingComplete(SystemTriggerType 참조) 트리거를 사용하여 업데이트 후 구성 변경(예: 앱의 데이터베이스 마이그레이션 및 백그라운드 작업 등록)을 실행하세요. 이때 가장 좋은 방법은 이전 버전의 앱에 연결된 백그라운드 작업의 등록을 취소하고(RemoveAccess 참조) 새 버전의 앱에 대한 백그라운드 작업을 등록하는(RequestAccessAsync 참조) 것입니다.

자세한 내용은 백그라운드 작업 지침을 참조하세요.

이벤트 처리기로 백그라운드 작업 완료 처리하기

앱으로 백그라운드 작업의 결과를 가져올 수 있도록 BackgroundTaskCompletedEventHandler에 메서드를 등록해야 합니다. 앱을 포그라운드에서 마지막으로 실행한 이후에 백그라운드 작업이 완료된 경우 앱을 시작하거나 다시 시작하면 표시된 메서드가 호출됩니다. (앱이 현재 포그라운드에 있는 동안 백그라운드 작업이 완료되면 OnCompleted 메서드가 즉시 호출됩니다.)

  1. 백그라운드 작업 완료를 처리할 OnCompleted 메서드를 작성하세요. 예를 들면 백그라운드 작업 결과로 인해 UI 업데이트가 이뤄질 수 있습니다. 이 예제에서 args 매개변수를 사용하지 않더라도, 아래에 나와 있는 메서드 공간은 OnCompleted 이벤트 처리기 메서드에 필요합니다.

다음 샘플 코드는 백그라운드 작업 완료를 인식하고, 메시지 문자열을 사용하는 예제 UI 업데이트 메서드를 호출합니다.

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 스레드를 대기할 일이 없도록 UI 업데이트를 비동기적으로 실행해야 합니다. 관련 예제는 백그라운드 작업 샘플의 UpdateUI 메서드를 참조하세요.

  1. 백그라운드 작업을 등록한 위치로 돌아가세요. 해당 코드 행 뒤에 새로운 BackgroundTaskCompletedEventHandler 개체를 추가하세요. OnCompleted 메서드를 BackgroundTaskCompletedEventHandler 생성자의 매개변수로 제공하세요.

다음 샘플 코드는 BackgroundTaskCompletedEventHandlerBackgroundTaskRegistration에 추가합니다.

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

앱 매니페스트에서 앱이 백그라운드 작업을 사용한다고 선언

앱으로 백그라운드 작업을 실행하려면 먼저 앱 매니페스트에서 각 백그라운드 작업을 선언해야 합니다. 앱이 매니페스트에 나열되지 않은 트리거를 사용하여 백그라운드 작업을 등록하려고 하는 경우 백그라운드 작업 등록이 실패하고 “런타임 클래스가 등록되지 않았습니다” 오류가 표시됩니다.

  1. Package.appxmanifest 파일을 열어서 패키지 매니페스트 디자이너를 여세요.
  2. 선언 탭을 여세요.
  3. 사용 가능한 선언 드롭다운에서 백그라운드 작업을 선택하고 추가를 클릭하세요.
  4. 시스템 이벤트 확인란을 선택하세요.
  5. 진입점: 텍스트 상자에 백그라운드 클래스의 이름 및 네임스페이스(이 예제의 경우 Tasks.ExampleBackgroundTask)를 입력합니다.
  6. 매니페스트 디자이너를 닫으세요.

다음 확장 요소는 백그라운드 작업을 등록하기 위해 Package.appxmanifest 파일에 추가됩니다.

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

요약 및 다음 단계

이제 백그라운드 작업 클래스를 작성하는 방법, 앱 내에서 백그라운드 작업을 등록하는 방법, 앱이 백그라운드 작업이 완료된 시기를 인식하게 하는 방법에 대한 기본 원칙을 이해해야 합니다. 앱이 백그라운드 작업을 성공적으로 등록할 수 있도록 애플리케이션 매니페스트를 업데이트하는 방법도 이해해야 합니다.

참고 항목

백그라운드 작업을 사용하는 완전하고 강력한 UWP 앱의 컨텍스트에서 유사한 코드 예제를 확인하려면 백그라운드 작업 샘플을 다운로드하세요.

API 참조, 백그라운드 작업 개념 지침, 백그라운드 작업을 사용하는 앱을 작성하기 위한 상세 지침은 다음 관련 토픽들을 참조하세요.

자세한 백그라운드 작업 지침 항목

백그라운드 작업 지침

백그라운드 작업 API 참조