アプリ ライフサイクル API を使用した電源管理

Windows App SDK のアプリ ライフサイクル API は、Microsoft.Windows.System.Power名前空間で、電源管理 API のセットを提供します。 これらの API は、アプリがデバイスの電源状態にどのように影響するかを可視化し、アプリでリソースの使用状況に関するインテリジェントな決定が行われるようにします。 たとえば、デバイスがバッテリー電源で実行されている間は、アプリによりこの API が使用され、リソースを大量に消費するバックグラウンド タスクが延期される場合があります。

電源管理 API では、既存の PowerSettingRegisterNotification 関数と同様のコールバックベースのモデルが使用されます。 コールバック モデルを使用すると、バックグラウンド アプリ、ヘッドレス アプリなど、すべてのアプリに対して API のリーチが拡張されます。

前提条件

Windows App SDK でアプリ ライフサイクル API を使用するには、次のようにします。

  1. Windows App SDK の最新リリースをダウンロードしてインストールします。 詳細については、「Windows App SDK 用ツールをインストールする」を参照してください。
  2. 手順に従って、最初の WinUI 3 プロジェクトを作成するか、既存のプロジェクトで Windows App SDK を使用します

イベントのサブスクライブと応答

次の例は、PowerManager イベントをサブスクライブして応答する方法を示しています。 このコードは、起動時に BatteryStatusChanged イベントをサブスクライブします。 その後、アプリは、現在の電源レベルを確認し、リソースの使用状況を適切に調整して、変更に応答します。 たとえば、バッテリーが低電力状態で放電した場合、アプリにより重要ではないバックグラウンド作業を延期される可能性があります。

Note

アプリは、いつでもこれらのイベントの登録と登録解除を行うことができますが、ほとんどのアプリでは、アプリの実行が継続されている限り、持続する WinMain のコールバックを設定する必要があります。

BOOL bWorkInProgress;
winrt::event_token batteryToken;
winrt::event_token powerToken;
winrt::event_token powerSourceToken;
winrt::event_token chargeToken;
winrt::event_token dischargeToken;

void RegisterPowerManagerCallbacks()
{
    batteryToken = PowerManager::BatteryStatusChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnBatteryStatusChanged(); });
    powerToken = PowerManager::PowerSupplyStatusChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnPowerSupplyStatusChanged(); });
    powerSourceToken = PowerManager::PowerSourceKindChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnPowerSourceKindChanged(); });
    chargeToken = PowerManager::RemainingChargePercentChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnRemainingChargePercentChanged(); });
    dischargeToken = PowerManager::RemainingDischargeTimeChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnRemainingDischargeTimeChanged(); });

    if (batteryToken && powerToken && powerSourceToken && chargeToken && dischargeToken)
    {
        OutputMessage(L"Successfully registered for state notifications");
    }
    else
    {
        OutputMessage(L"Failed to register for state notifications");
    }
}

void OnBatteryStatusChanged()
{
    const size_t statusSize = 16;
    WCHAR szStatus[statusSize];
    wmemset(&(szStatus[0]), 0, statusSize);

    BatteryStatus batteryStatus = PowerManager::BatteryStatus();
    int remainingCharge = PowerManager::RemainingChargePercent();
    switch (batteryStatus)
    {
    case BatteryStatus::Charging:
        wcscpy_s(szStatus, L"Charging");
        break;
    case BatteryStatus::Discharging:
        wcscpy_s(szStatus, L"Discharging");
        break;
    case BatteryStatus::Idle:
        wcscpy_s(szStatus, L"Idle");
        break;
    case BatteryStatus::NotPresent:
        wcscpy_s(szStatus, L"NotPresent");
        break;
    }

    OutputFormattedMessage(
        L"Battery status changed: %s, %d%% remaining", 
        szStatus, remainingCharge);
    DetermineWorkloads();
}

void OnPowerSupplyStatusChanged()
{
//...etc
}

複数のステータス値に基づいてアプリ ロジックを構成する

PowerManager イベントは比較的低レベルであり、シナリオによっては、呼び出された 1 つのイベント ハンドラーでは、アプリで動作方法が決定されるために十分な情報が提供されないことがあります。 この例では、デバイスが電源に接続されていないときに、PowerSupplyStatusChanged イベントを呼び出すことができます。 その場合、アプリは、続行する方法を決定する前に、現在のバッテリーの状態を確認する必要があります。

void DetermineWorkloads()
{
    BatteryStatus batteryStatus = PowerManager::BatteryStatus();
    int remainingCharge = PowerManager::RemainingChargePercent();
    PowerSupplyStatus powerStatus = PowerManager::PowerSupplyStatus();
    PowerSourceKind powerSource = PowerManager::PowerSourceKind();

    if ((powerSource == PowerSourceKind::DC 
        && batteryStatus == BatteryStatus::Discharging 
        && remainingCharge < 25)
        || (powerSource == PowerSourceKind::AC
        && powerStatus == PowerSupplyStatus::Inadequate))
    {
        // The device is not in a good battery/power state, 
        // so we should pause any non-critical work.
        PauseNonCriticalWork();
    }
    else if ((batteryStatus != BatteryStatus::Discharging && remainingCharge > 75)
        && powerStatus != PowerSupplyStatus::Inadequate)
    {
        // The device is in good battery/power state,
        // so let's kick of some high-power work.
        StartPowerIntensiveWork();
    }
}

画面の状態を確認する

PowerManager クラスにより、アプリの電力使用状況に関連するその他のデバイスの状態に関する情報が提供されます。 たとえば、アプリは、デバイスのディスプレイがオフになっているときにグラフィックス処理を無効にすることができます。

void OnDisplayStatusChanged()
{
    const size_t statusSize = 16;
    WCHAR szStatus[statusSize];
    wmemset(&(szStatus[0]), 0, statusSize);

    DisplayStatus displayStatus = PowerManager::DisplayStatus();
    switch (displayStatus)
    {
    case DisplayStatus::Dimmed:
        wcscpy_s(szStatus, L"Dimmed");
        break;
    case DisplayStatus::Off:
        wcscpy_s(szStatus, L"Off");
        break;
    case DisplayStatus::On:
        wcscpy_s(szStatus, L"On");
        break;
    }

    OutputFormattedMessage(
        L"Display status changed: %s", szStatus);
    if (displayStatus == DisplayStatus::Off)
    {
        // The screen is off, let's stop rendering foreground graphics,
        // and instead kick off some background work now.
        StopUpdatingGraphics();
        StartDoingBackgroundWork();
    }
}

イベントのサブスクライブ解除

アプリは、ライフサイクル中に通知の登録と登録解除を行うことができます。 アプリがライフサイクル全体で電源状態の通知を受信する必要がない場合は、言語の優先イベント登録管理システムを使用します。

void UnregisterPowerManagerCallbacks()
{
    OutputMessage(L"Unregistering state notifications");
    PowerManager::BatteryStatusChanged(batteryToken);
    PowerManager::PowerSupplyStatusChanged(powerToken);
    PowerManager::PowerSourceKindChanged(powerSourceToken);
    PowerManager::RemainingChargePercentChanged(chargeToken);
    PowerManager::RemainingDischargeTimeChanged(dischargeToken);
}