앱 수명 주기 API를 통해 전원 관리

Windows App SDK의 앱 수명 주기 API는 Microsoft.Windows.System.Power 네임스페이스에서 전원 관리 API 세트를 제공합니다. 이러한 API는 앱이 디바이스의 전원 상태에 미치는 영향을 파악하고 앱에서 리소스 사용에 대한 지능적인 결정을 내릴 수 있도록 합니다. 예를 들어 앱은 이 API를 사용하여 디바이스가 배터리 전원으로 실행되는 동안 리소스 집약적인 백그라운드 작업을 연기할 수 있습니다.

전원 관리 API는 기존 PowerSettingRegisterNotification 함수와 비슷한 콜백 기반 모델을 사용합니다. 콜백 모델을 사용하면 백그라운드 앱, 헤드리스 앱 등을 포함한 모든 앱으로 API 범위가 확장됩니다.

필수 조건

Windows App SDK에서 앱 수명 주기 API를 사용하려면 다음을 수행합니다.

  1. Windows App SDK의 최신 릴리스를 다운로드하여 설치합니다. 자세한 내용은 Windows 앱 SDK용 도구 설치를 참조하세요.
  2. 지침에 따라 첫 번째 WinUI 3 프로젝트를 만들거나 기존 프로젝트에서 Windows 앱 SDK를 사용합니다.

이벤트 구독 및 대응

다음 예제에서는 PowerManager 이벤트를 구독하고 대응하는 방법을 보여 줍니다. 이 코드는 시작하는 동안 BatteryStatusChanged 이벤트를 구독합니다. 그런 다음, 앱은 현재 전력 수준을 확인하고 리소스 사용량을 적절하게 조정하여 변화에 대응합니다. 예를 들어 배터리가 저전력 상태에서 방전되는 경우 앱은 중요하지 않은 백그라운드 작업을 연기할 수 있습니다.

참고 항목

앱은 언제든지 이러한 이벤트를 등록 및 등록 취소할 수 있지만 대부분의 앱은 앱이 계속 실행되는 한 지속되는 콜백을 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 이벤트는 상대적으로 낮은 수준이며, 일부 시나리오에서는 호출되는 단일 이벤트 처리기가 앱이 작동 방법을 결정하는 데 충분한 정보를 제공하지 않을 수 있습니다. 이 예제에서 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);
}