다음을 통해 공유


WNS(Windows 푸시 알림 서비스) 개요

WNS(Windows 푸시 알림 서비스)를 사용하면 타사 개발자가 자체 클라우드 서비스에서 알림, 타일, 배지 및 원시 업데이트를 보낼 수 있습니다. 이렇게 하면 전원 효율적이고 신뢰할 수 있는 방식으로 사용자에게 새 업데이트를 제공하는 메커니즘이 제공됩니다.

작동 방식

다음 다이어그램은 푸시 알림을 보내기 위한 전체 데이터 흐름을 보여줍니다. 여기에는 다음 단계가 포함됩니다.

  1. 앱이 WNS에서 푸시 알림 채널을 요청합니다.
  2. Windows는 WNS에 알림 채널을 만들도록 요청합니다. 이 채널은 URI(Uniform Resource Identifier) 형식으로 호출 디바이스로 반환됩니다.
  3. 알림 채널 URI는 WNS에서 앱으로 반환됩니다.
  4. 앱은 URI를 사용자 고유의 클라우드 서비스로 보냅니다. 그런 다음 알림을 보낼 때 URI에 액세스할 수 있도록 자체 클라우드 서비스에 URI를 저장합니다. URI는 사용자 고유의 앱과 사용자 고유의 서비스 간의 인터페이스입니다. 안전하고 안전한 웹 표준을 사용하여 이 인터페이스를 구현하는 것은 사용자의 책임입니다.
  5. 클라우드 서비스에 보낼 업데이트가 있는 경우 채널 URI를 사용하여 WNS에 알깁니다. 이 작업은 SSL(Secure Sockets Layer)을 통해 알림 페이로드를 포함한 HTTP POST 요청을 실행하여 수행됩니다. 이 단계에서는 인증이 필요합니다.
  6. WNS는 요청을 수신하고 해당 디바이스에 알림을 라우팅합니다.

푸시 알림 에 대한 데이터 흐름 다이어그램

앱 등록 및 클라우드 서비스에 대한 자격 증명 수신

WNS를 사용하여 알림을 보내기 전에, 앱을 스토어 대시보드에 등록해야 합니다,여기에 설명된 대로.

알림 채널 요청

푸시 알림을 받을 수 있는 앱이 실행되면 먼저 CreatePushNotificationChannelForApplicationAsync통해 알림 채널을 요청해야 합니다. 전체 토론 및 예제 코드는 알림 채널요청, 만들기 및 저장하는 방법을 참조하세요. 이 API는 호출 애플리케이션 및 해당 타일에 고유하게 연결되고 모든 알림 유형을 보낼 수 있는 채널 URI를 반환합니다.

앱이 채널 URI를 성공적으로 만든 후 이 URI와 연결되어야 하는 앱별 메타데이터와 함께 클라우드 서비스로 보냅니다.

Important notes

  • 앱에 대한 알림 채널 URI가 항상 동일하게 유지된다는 보장은 없습니다. 앱이 실행될 때마다 새 채널을 요청하고, URI가 변경되면 서비스를 업데이트할 것을 권장합니다. 개발자는 채널 URI를 수정해서는 안 되며 이를 블랙박스 문자열로 간주해야 합니다. 현재 채널 URI는 30일 후에 만료됩니다. Windows 10 앱이 백그라운드에서 정기적으로 채널을 갱신하는 경우, Windows 8.1용 푸시 및 정기 알림 샘플을 다운로드하여 소스 코드 및/또는 그 패턴을 다시 사용할 수 있습니다.
  • 클라우드 서비스와 클라이언트 앱 간의 인터페이스는 개발자가 구현합니다. 앱은 자체 서비스를 사용하여 인증 프로세스를 거치고 HTTPS와 같은 보안 프로토콜을 통해 데이터를 전송하는 것이 좋습니다.
  • 클라우드 서비스는 항상 채널 URI에서 "notify.windows.com" 도메인을 사용하는지 확인해야 합니다. 서비스는 다른 도메인의 채널에 알림을 푸시해서는 안 됩니다. 앱의 콜백이 손상된 경우, 악의적인 공격자가 채널 URI를 제출하여 WNS를 스푸핑(속이기)할 수 있습니다. 도메인을 검사하지 않으면 클라우드 서비스가 이 공격자에게 정보를 무의식적으로 공개할 수 있습니다. 채널 URI의 하위 도메인은 변경될 수 있으며 채널 URI의 유효성을 검사할 때 고려해서는 안 됩니다.
  • 클라우드 서비스가 만료된 채널에 알림을 전달하려고 하면 WNS는 응답 코드 410반환합니다. 해당 코드에 대한 응답으로 서비스는 더 이상 해당 URI에 알림을 보내려고 시도하지 않아야 합니다.

클라우드 서비스 인증

알림을 보내려면 WNS를 통해 클라우드 서비스를 인증해야 합니다. 이 프로세스의 첫 번째 단계는 Microsoft Store 대시보드에 앱을 등록할 때 발생합니다. 등록 프로세스 중에 앱에 SID(패키지 보안 식별자) 및 비밀 키가 제공됩니다. 이 정보는 클라우드 서비스에서 WNS로 인증하는 데 사용됩니다.

WNS 인증 체계는 OAuth 2.0 프로토콜의 클라이언트 자격 증명 프로필을 사용하여 구현됩니다. 클라우드 서비스는 자격 증명(패키지 SID 및 비밀 키)을 제공하여 WNS로 인증합니다. 그 대가로 액세스 토큰을 받습니다. 이 액세스 토큰을 사용하면 클라우드 서비스에서 알림을 보낼 수 있습니다. 토큰은 WNS로 전송되는 모든 알림 요청에 필요합니다.

높은 수준에서 정보 체인은 다음과 같습니다.

  1. 클라우드 서비스는 OAuth 2.0 프로토콜에 따라 HTTPS를 통해 해당 자격 증명을 WNS로 보냅니다. 그러면 WNS를 사용하여 서비스를 인증합니다.
  2. 인증에 성공하면 WNS는 액세스 토큰을 반환합니다. 이 액세스 토큰은 만료될 때까지 모든 후속 알림 요청에서 사용됩니다.

wns 다이어그램 클라우드 서비스 인증

WNS를 사용한 인증에서 클라우드 서비스는 SSL(Secure Sockets Layer)을 통해 HTTP 요청을 제출합니다. 매개 변수는 "application/x-www-for-urlencoded" 형식으로 제공됩니다. 다음 예제와 같이 "client_id" 필드에 패키지 SID를 제공하고 "client_secret" 필드에 비밀 키를 제공합니다. 구문 세부 정보는 액세스 토큰 요청 참조를 참조하세요.

Note

이는 사용자 고유의 코드에서 성공적으로 사용할 수 있는 잘라내기 및 붙여넣기 코드가 아니라 예제일 뿐입니다. 

 POST /accesstoken.srf HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 Host: https://login.live.com
 Content-Length: 211
 
 grant_type=client_credentials&client_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-1345238579-3987825745-2155616079-650196962&client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7&scope=notify.windows.com

WNS는 클라우드 서비스를 인증하고 성공하면 "200 OK"라는 응답을 보냅니다. 액세스 토큰은 "application/json" 미디어 형식을 사용하여 HTTP 응답 본문에 포함된 매개 변수에 반환됩니다. 서비스에서 액세스 토큰을 받은 후에는 알림을 보낼 준비가 된 것입니다.

다음 예제에서는 액세스 토큰을 포함하여 성공적인 인증 응답을 보여 주는 예제입니다. 구문 세부 사항은 푸시 알림 서비스 요청 및 응답 헤더을 참조하십시오.

 HTTP/1.1 200 OK   
 Cache-Control: no-store
 Content-Length: 422
 Content-Type: application/json
 
 {
     "access_token":"EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=", 
     "token_type":"bearer"
 }

Important notes

  • 이 절차에서 지원되는 OAuth 2.0 프로토콜은 초안 버전 V16을 따릅니다.
  • OAuth RFC(주석 요청)는 "클라이언트"라는 용어를 사용하여 클라우드 서비스를 참조합니다.
  • OAuth 초안이 완료될 때 이 절차가 변경될 수 있습니다.
  • 액세스 토큰은 여러 알림 요청에 다시 사용할 수 있습니다. 이렇게 하면 클라우드 서비스가 한 번만 인증하여 많은 알림을 보낼 수 있습니다. 그러나 액세스 토큰이 만료되면 클라우드 서비스는 새 액세스 토큰을 받기 위해 다시 인증해야 합니다.

알림 보내기

클라우드 서비스는 채널 URI를 사용하여 사용자에 대한 업데이트가 있을 때마다 알림을 보낼 수 있습니다.

위에서 설명한 액세스 토큰은 여러 알림 요청에 다시 사용할 수 있습니다. 클라우드 서버는 모든 알림에 대해 새 액세스 토큰을 요청할 필요가 없습니다. 액세스 토큰이 만료된 경우 알림 요청은 오류를 반환합니다. 액세스 토큰이 거부된 경우 알림을 두 번 이상 다시 보내지 않는 것이 좋습니다. 이 오류가 발생하면 새 액세스 토큰을 요청하고 알림을 다시 보내야 합니다. 정확한 오류 코드는 푸시 알림 응답 코드참조하세요.

  1. 클라우드 서비스는 채널 URI에 대한 HTTP POST를 만듭니다. 이 요청은 SSL을 통해 수행되어야 하며 필요한 헤더 및 알림 페이로드를 포함해야 합니다. 권한 부여 헤더에는 권한 부여를 위해 획득한 액세스 토큰이 포함되어야 합니다.

    예제 요청이 여기에 표시됩니다. 구문 세부 정보는푸시 알림 응답 코드 참조하세요.

    알림 페이로드 작성에 대한 자세한 내용은 빠른 시작: 푸시 알림보내기를 참조하세요. 타일, 알림 메시지 또는 배지 푸시 알림의 페이로드는 또는 레거시 타일 스키마정의된 각 적응형 타일 스키마를 준수하는 XML 콘텐츠로 제공됩니다. 원시 알림의 페이로드에 지정된 구조가 없습니다. 엄격하게 앱에서 정의됩니다.

     POST https://cloud.notify.windows.com/?token=AQE%bU%2fSjZOCvRjjpILow%3d%3d HTTP/1.1
     Content-Type: text/xml
     X-WNS-Type: wns/tile
     Authorization: Bearer EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=
     Host: cloud.notify.windows.com
     Content-Length: 24
    
     <body>
     ....
    
  2. WNS는 알림이 수신되었으며 사용 가능한 다음 기회에 전달될 것임을 나타내기 위해 응답합니다. 그러나 WNS는 디바이스 또는 애플리케이션에서 알림을 받았다는 엔드투엔드 확인을 제공하지 않습니다.

이 다이어그램은 데이터 흐름을 보여 줍니다.

알림을 보내기 위한 wns 다이어그램

Important notes

  • WNS는 알림의 안정성 또는 대기 시간을 보장하지 않습니다.
  • 알림에는 기밀, 중요한 데이터 또는 개인 데이터가 포함되어서는 안 됩니다.
  • 알림을 보내려면 클라우드 서비스가 먼저 WNS를 사용하여 인증하고 액세스 토큰을 받아야 합니다.
  • 액세스 토큰은 클라우드 서비스가 토큰을 만든 단일 앱에만 알림을 보낼 수 있도록 허용합니다. 하나의 액세스 토큰을 사용하여 여러 앱에서 알림을 보낼 수 없습니다. 따라서 클라우드 서비스가 여러 앱을 지원하는 경우 각 채널 URI에 알림을 푸시할 때 앱에 대한 올바른 액세스 토큰을 제공해야 합니다.
  • 디바이스가 오프라인 상태인 경우 기본적으로 WNS는 각 채널 URI에 대해 알림 유형(타일, 배지, 토스트)별로 하나씩 저장하며, 원시 알림은 저장하지 않습니다.
  • 알림 콘텐츠가 사용자에게 개인 설정된 시나리오에서 WNS는 클라우드 서비스가 해당 업데이트를 받을 때 즉시 해당 업데이트를 보내는 것이 좋습니다. 이 시나리오의 예로는 소셜 미디어 피드 업데이트, 인스턴트 통신 초대, 새 메시지 알림 또는 경고가 있습니다. 또는 동일한 일반 업데이트가 사용자의 큰 하위 집합에 자주 전달되는 시나리오가 있을 수 있습니다. 예를 들어 날씨, 주식 및 뉴스 업데이트입니다. WNS 지침은 이러한 업데이트 빈도를 30분마다 최대 1개까지 지정합니다. 최종 사용자 또는 WNS는 더 잦은 일상 업데이트가 부담스럽다고 판단할 수 있습니다.
  • Windows Notification Platform은 소켓을 활성 상태와 정상 상태로 유지하기 위해 WNS와 주기적인 데이터 연결을 유지합니다. 알림 채널을 요청하거나 사용하는 애플리케이션이 없으면 소켓이 만들어지지 않습니다.

타일 및 배지 알림 만료

기본적으로 타일 및 배지 알림은 다운로드 후 3일 후에 만료됩니다. 알림이 만료되면 콘텐츠가 타일 또는 큐에서 제거되고 사용자에게 더 이상 표시되지 않습니다. 타일의 콘텐츠가 관련성이 떨어지기 전에 만료되도록, 모든 타일 및 배지 알림에 앱에 적합한 만료 시간을 설정하는 것이 모범 사례입니다. 명시적 만료 시간은 정의된 수명이 있는 콘텐츠에 필수적입니다. 또한 클라우드 서비스가 알림 전송을 중지하거나 사용자가 오랜 기간 동안 네트워크에서 연결을 끊는 경우 부실 콘텐츠를 제거할 수 있습니다.

클라우드 서비스는 X-WNS-TTL HTTP 헤더를 설정하여 알림이 전송된 후 유효한 상태로 유지되는 시간(초)을 지정하여 각 알림에 대한 만료를 설정할 수 있습니다. 자세한 내용은 푸시 알림 서비스 요청 및 응답 헤더을 참조하세요.

예를 들어 주식 시장의 활성 거래일 동안 주식 가격 업데이트의 만료를 보내는 간격의 두 배로 설정할 수 있습니다(예: 반시간마다 알림을 보내는 경우 수신 후 1시간). 또 다른 예로, 뉴스 앱은 하루가 일일 뉴스 타일 업데이트에 적절한 만료 시간이라고 판단할 수 있습니다.

푸시 알림 및 배터리 절약 모드

배터리 절약 모드는 디바이스에서 백그라운드 작업을 제한하여 배터리 수명을 연장합니다. Windows 10을 사용하면 배터리가 지정된 임계값 아래로 떨어질 때 배터리 절약 모드가 자동으로 켜지도록 설정할 수 있습니다. 배터리 절약 모드가 켜져 있으면 푸시 알림 수신이 비활성화되어 에너지를 절약할 수 있습니다. 그러나 이에 대한 몇 가지 예외가 있습니다. 다음 Windows 10 배터리 보호기 설정(설정 앱에서 찾을 수 있습니다)을 사용하면 배터리 절약 모드가 켜져 있는 경우에도 앱이 푸시 알림을 받을 수 있습니다.

  • 배터리 보호기있는 동안 모든 앱에서 푸시 알림 허용: 이 설정을 사용하면 배터리 절약 모드가 켜져 있는 동안 모든 앱에서 푸시 알림을 받을 수 있습니다. 이 설정은 데스크톱 버전(Home, Pro, Enterprise 및 Education)용 Windows 10에만 적용됩니다.
  • 항상 허용되는: 이 설정을 사용하면 푸시 알림 수신을 포함하여 배터리 절약 모드가 켜져 있는 동안 특정 앱이 백그라운드에서 실행될 수 있습니다. 이 목록은 사용자가 수동으로 유지 관리합니다.

이 두 설정의 상태를 확인할 수 있는 방법은 없지만 배터리 절약 모드의 상태를 확인할 수 있습니다. Windows 10에서 EnergySaverStatus 속성을 사용하여 배터리 절약 모드 상태를 확인합니다. 앱은 EnergySaverStatusChanged 이벤트를 사용하여 배터리 절약 장치의 변경 내용을 수신 대기할 수도 있습니다.

앱이 푸시 알림에 크게 의존하는 경우 배터리 절약 모드가 켜져 있는 동안 알림을 받지 못할 수 있음을 사용자에게 알리고배터리 절약 모드 설정을 쉽게 조정할 수 있도록 하는 것이 좋습니다. ms-settings:batterysaver-settingsWindows 10에서 배터리 절약 모드 설정 URI 체계를 사용하여 설정 앱에 편리한 링크를 제공할 수 있습니다.

Tip

배터리 절약 모드 설정에 대해 사용자에게 알릴 때 나중에 메시지를 표시하지 않는 방법을 제공하는 것이 좋습니다. 예를 들어, 다음 예제의 dontAskMeAgainBox 확인란은 사용자의 기본 설정을 LocalSettings에 유지합니다.

다음은 Windows 10에서 배터리 절약 모드가 켜져 있는지 여부를 확인하는 방법의 예입니다. 이 예제는 사용자에게 알리고 설정 앱을 실행하여 배터리 절약 모드 설정으로 이동합니다. dontAskAgainSetting를 사용하여 사용자가 다시 알림을 받지 않으려면 메시지를 숨길 수 있습니다.

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Windows.System;
using Windows.System.Power;
...
...
async public void CheckForEnergySaving()
{
   //Get reminder preference from LocalSettings
   bool dontAskAgain;
   var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
   object dontAskSetting = localSettings.Values["dontAskAgainSetting"];
   if (dontAskSetting == null)
   {  // Setting does not exist
      dontAskAgain = false;
   }
   else
   {  // Retrieve setting value
      dontAskAgain = Convert.ToBoolean(dontAskSetting);
   }
   
   // Check if battery saver is on and that it's okay to raise dialog
   if ((PowerManager.EnergySaverStatus == EnergySaverStatus.On)
         && (dontAskAgain == false))
   {
      // Check dialog results
      ContentDialogResult dialogResult = await saveEnergyDialog.ShowAsync();
      if (dialogResult == ContentDialogResult.Primary)
      {
         // Launch battery saver settings (settings are available only when a battery is present)
         await Launcher.LaunchUriAsync(new Uri("ms-settings:batterysaver-settings"));
      }

      // Save reminder preference
      if (dontAskAgainBox.IsChecked == true)
      {  // Don't raise dialog again
         localSettings.Values["dontAskAgainSetting"] = "true";
      }
   }
}
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.System.Power.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Navigation.h>
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage;
using namespace winrt::Windows::System;
using namespace winrt::Windows::System::Power;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;
...
winrt::fire_and_forget CheckForEnergySaving()
{
    // Get reminder preference from LocalSettings.
    bool dontAskAgain{ false };
    auto localSettings = ApplicationData::Current().LocalSettings();
    IInspectable dontAskSetting = localSettings.Values().Lookup(L"dontAskAgainSetting");
    if (!dontAskSetting)
    {
        // Setting doesn't exist.
        dontAskAgain = false;
    }
    else
    {
        // Retrieve setting value
        dontAskAgain = winrt::unbox_value<bool>(dontAskSetting);
    }

    // Check whether battery saver is on, and whether it's okay to raise dialog.
    if ((PowerManager::EnergySaverStatus() == EnergySaverStatus::On) && (!dontAskAgain))
    {
        // Check dialog results.
        ContentDialogResult dialogResult = co_await saveEnergyDialog().ShowAsync();
        if (dialogResult == ContentDialogResult::Primary)
        {
            // Launch battery saver settings
            // (settings are available only when a battery is present).
            co_await Launcher::LaunchUriAsync(Uri(L"ms-settings:batterysaver-settings"));
        }

        // Save reminder preference.
        if (dontAskAgainBox().IsChecked())
        {
            // Don't raise the dialog again.
            localSettings.Values().Insert(L"dontAskAgainSetting", winrt::box_value(true));
        }
    }
}

이 예제에 소개된 ContentDialog 대한 XAML입니다.

<ContentDialog x:Name="saveEnergyDialog"
               PrimaryButtonText="Open battery saver settings"
               SecondaryButtonText="Ignore"
               Title="Battery saver is on."> 
   <StackPanel>
      <TextBlock TextWrapping="WrapWholeWords">
         <LineBreak/><Run>Battery saver is on and you may 
          not receive push notifications.</Run><LineBreak/>
         <LineBreak/><Run>You can choose to allow this app to work normally
         while in battery saver, including receiving push notifications.</Run>
         <LineBreak/>
      </TextBlock>
      <CheckBox x:Name="dontAskAgainBox" Content="OK, got it."/>
   </StackPanel>
</ContentDialog>