アウトプロセス バックグラウンド タスクの作成と登録

重要な API

バックグラウンド タスク クラスを作成し、アプリがフォアグラウンドにない場合に実行するように登録します。 このトピックでは、アプリのプロセスとは別のプロセスで実行されるバックグラウンド タスクを作成して登録する方法について説明します。 フォアグラウンド アプリケーションでバックグラウンド処理を直接実行するには、「 作成してプロセス内のバックグラウンド タスクを登録する」を参照してください

Note

バックグラウンド タスクを使ってバックグラウンドでメディアを再生する場合、Windows 10 バージョン 1607 で簡単に行うことができる機能強化について、「バックグラウンドでのメディアの再生」をご覧ください。

Note

.NET 6 以降を使用して C# デスクトップ アプリケーションでアウトプロセス バックグラウンド タスクを実装する場合は、C#/WinRT 作成サポートを使用してWindows ランタイム コンポーネントを作成します。 これは、Windows アプリ SDK、WinUI 3、WPF、または WinForms を使用するアプリに適用されます。 例については、 Background タスクのサンプル を参照してください。

バックグラウンド タスク クラスを作成する

IBackgroundTask インターフェイスを実装するクラスを記述することで、バックグラウンドでコードを実行できます。 このコードは、SystemTriggerMaintenanceTrigger などを使って特定のイベントをトリガーすると実行されます。

次の手順では、 IBackgroundTask インターフェイスを実装する新しいクラスを記述する方法を示します。

  1. バックグラウンド タスク用の新しいプロジェクトを作成し、ソリューションに追加します。 このためには、ソリューション エクスプローラーのソリューション ノードを右クリックし、[追加]>[新しいプロジェクト] を順に選びます。 プロジェクトの種類として [Windows ランタイム コンポーネント] を選び、プロジェクトに名前を付け、[OK] をクリックします。
  2. ユニバーサル Windows プラットフォーム (UWP) アプリ プロジェクトからバックグラウンド タスク プロジェクトを参照します。 C# または C++ のアプリの場合、アプリ プロジェクトで [参照] を右クリックして [新しい参照の追加] をクリックします。 [ ソリューションProjects] を選択し バックグラウンド タスク プロジェクトの名前を選択し、[ Ok] をクリック
  3. バックグラウンド タスク プロジェクトに、IBackgroundTask インターフェイスを実装する新しいクラスを追加します。 IBackgroundTask.Run メソッドは、指定のイベントがトリガーされたときに呼び出される必須のエントリ ポイントです。このメソッドは、各バックグラウンド タスクに必要です。

Note

バックグラウンド タスク クラス自体と、バックグラウンド タスク プロジェクト内のその他すべてのクラスは、sealed (または final の) public クラスである必要があります。

次のサンプル コードは、バックグラウンド タスク クラスの基本的な開始点を示しています。

// 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. バックグラウンド タスクで非同期コードを実行する場合は、バックグラウンド タスクで遅延を使用する必要があります。 遅延を使わない場合、非同期処理の実行が完了する前に Run メソッドから制御が戻されると、バックグラウンド タスク プロセスが予期せずに終了することがあります。

非同期メソッドを呼び出す前に、Run メソッド内で遅延を要求します。 クラスのデータ メンバーに遅延を保存して、非同期メソッドからアクセスできるようにします。 非同期コードの完了後に遅延完了を宣言します。

次のサンプル コードでは、遅延を取得して保存し、非同期コードが完了した時点で解放します。

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

Note

C# では、バックグラウンド タスクの非同期メソッドは、 async/await キーワードを使用して呼び出すことができます。 C++/CX では、タスク チェーンを使うことで同様の結果が得られます。

非同期パターンの詳細については、「 Asynchronous プログラミングを参照してください。 遅延を使用してバックグラウンド タスクを早期に停止させないようにする方法のその他の例については、 バックグラウンド タスクのサンプルを参照してください。

次の手順は、いずれかのアプリ クラス (たとえば、MainPage.xaml.cs) で完了します。

Note

バックグラウンド タスクを登録するための専用の関数を作成することもできます (「バックグラウンド タスクの登録」を参照)。 その場合、次の 3 つの手順は不要です。単にトリガーを作成し、タスクの名前とタスクのエントリ ポイント、(必要に応じて) 条件と併せて登録関数に渡すだけで済みます。

実行するバックグラウンド タスクを登録する

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

Note

ユニバーサル 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);
}

Note

UI スレッドを保持しないように、UI の更新を非同期的に実行する必要があります。 例については、 background タスク サンプルの UpdateUI メソッドを参照してください。

  1. バックグラウンド タスクを登録した場所に戻ります。 そのコード行の後に、新しい BackgroundTaskCompletedEventHandler オブジェクトを追加します。 BackgroundTaskCompletedEventHandler コンストラクターのパラメーターとして OnCompleted メソッドを指定します。

次のサンプル コードでは、 BackgroundTaskCompletedEventHandlerBackgroundTaskRegistration に追加します。

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

アプリがバックグラウンド タスクを使うことをアプリ マニフェストで宣言する

アプリでバックグラウンド タスクを実行するには、アプリ マニフェストで各バックグラウンド タスクを宣言する必要があります。 マニフェストにないトリガーを使用してバックグラウンド タスクを登録しようとすると、バックグラウンド タスクの登録は、"ランタイム クラスが登録されていません" というエラーで失敗します。

  1. Package.appxmanifest という名前のファイルを開いて、パッケージ マニフェスト デザイナーを開きます。
  2. [宣言] タブを開きます。
  3. [ Available Declarations ドロップダウンから Background Tasks を選択し、 [追加] をクリックします。
  4. System イベントチェック ボックスをオンにします。
  5. [エントリ ポイント] ボックスに、バックグラウンド クラスの名前空間と名前を入力します。この例の場合、Tasks.ExampleBackgroundTask です。
  6. マニフェスト デザイナーを閉じます。

次の Extensions 要素が Package.appxmanifest ファイルに追加され、バックグラウンド タスクが登録されます。

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

まとめと次のステップ

バックグラウンド タスク クラスを記述する方法、アプリ内からバックグラウンド タスクを登録する方法、およびバックグラウンド タスクが完了したときにアプリで認識されるようにする方法の基本を理解する必要があります。 また、アプリがバックグラウンド タスクを正常に登録できるように、アプリケーション マニフェストを更新する方法についても理解する必要があります。

Note

バックグラウンド タスクのサンプルをダウンロードしてバックグラウンド タスクを使用する完全で堅牢な UWP アプリのコンテキストで同様のコード例を確認します。

API リファレンス、バックグラウンド タスクの概念ガイダンス、およびバックグラウンド タスクを使用するアプリを記述するための詳細な手順については、次の関連トピックを参照してください。

バックグラウンド タスクの詳細な説明トピック

バックグラウンド タスクのガイダンス

バックグラウンド タスク API リファレンス