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

重要な API

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

注意

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

注意

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

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

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

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

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

注意

バックグラウンド タスク クラス自体と、バックグラウンド タスク プロジェクト内のその他すべてのクラスは、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();
    });
}

注意

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

非同期パターンについて詳しくは、「非同期プログラミング」をご覧ください。 遅延を使ってバックグラウンド タスクの早期停止を防ぐ方法に関するその他の例については、バックグラウンド タスクのサンプルに関するページをご覧ください。

次の手順はいずれかのアプリ クラス (MainPage.xaml.cs など) で実行します。

注意

バックグラウンド タスクを登録するための専用の関数を作成することもできます (「バックグラウンド タスクの登録」を参照)。 その場合、次の 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();

注意

ユニバーサル 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 オブジェクトを追加します。 BackgroundTaskCompletedEventHandler コンストラクターのパラメーターとして OnCompleted メソッドを指定します。

次のサンプル コードにより、BackgroundTaskRegistrationBackgroundTaskCompletedEventHandler が追加されます。

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. マニフェスト デザイナーを閉じます。

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

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

まとめと次のステップ

ここでは、バックグラウンド タスク クラスの記述方法、アプリ内からバックグラウンド タスクを登録する方法、バックグラウンド タスクが完了したことをアプリで認識する方法の基本について学習しました。 また、アプリで適切にバックグラウンド タスクを登録できるように、アプリ マニフェストを更新する方法についても学習しました。

注意

バックグラウンド タスクのサンプルをダウンロードして、バックグラウンド タスクを使う完全で堅牢な UWP アプリのコンテキストで類似のコード例を確認してください。

API リファレンス、バックグラウンド タスクの概念的ガイダンス、バックグラウンド タスクを使ったアプリの作成に関する詳しい説明については、次の関連するトピックをご覧ください。

バックグラウンド タスクに関する手順を詳しく説明するトピック

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

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