Поделиться через


Краткое руководство. Push-уведомления в Windows App SDK

В этом кратком руководстве вы создадите классическое приложение Windows, которое отправляет и получает push-уведомления с помощью пакета SDK для приложений Windows.

Необходимые компоненты

Пример приложения

В этом кратком руководстве описывается добавление поддержки push-уведомлений в приложение. Ознакомьтесь с примером кода из этого краткого руководства в контексте примеров приложений, найденных на сайте GitHub.

Справочник по API

Справочная документация по API для push-уведомлений см. в пространстве имен Microsoft.Windows.PushNotifications.

Настройка удостоверения приложения в Azure Active Directory (AAD)

Push-уведомления в пакете SDK для приложений Windows используют удостоверения из Azure Active Directory (AAD). Учетные данные Azure необходимы при запросе URI канала WNS и при запросе маркеров доступа для отправки push-уведомлений. Примечание. Мы не поддерживаем push-уведомления пакета SDK для Приложений Windows в Центре партнеров Майкрософт.

Шаг 1. Создание регистрации приложения AAD

Войдите в учетную запись Azure и создайте ресурс регистрации приложений AAD. Выберите Создать регистрацию.

Шаг 2. Укажите имя и выберите параметр с несколькими клиентами

  1. Введите имя приложения

  2. Для push-уведомлений требуется параметр с несколькими клиентами, поэтому выберите это.

    1. Дополнительные сведения о клиентах см. в разделе "Кто может войти в приложение?".
  3. Нажмите кнопку Зарегистрировать.

  4. Запишите идентификатор приложения (клиента), так как это ваш приложение Azure Id, который вы будете использовать во время регистрации активации и запроса маркера доступа.

  5. Запишите идентификатор каталога (клиента), так как это идентификатор Клиента Azure , который вы будете использовать при запросе маркера доступа.

    Внимание

    Клиент регистрации приложений AADЗапишите идентификатор приложения (клиента) и идентификатор каталога (клиента).

  6. Запишите идентификатор объекта, так как это azure ObjectId , который вы будете использовать при запросе запроса канала. Обратите внимание, что это НЕ идентификатор объекта, указанный на странице Essentials . Вместо этого, чтобы найти правильный идентификатор объекта, щелкните имя приложения в управляемом приложении в поле локального каталога на странице Essentials :

    Снимок экрана: управляемое приложение в локальном каталоге на странице Essentials

    Снимок экрана: поле

    Примечание.

    Субъект-служба требуется для получения идентификатора объекта, если он не связан с приложением, выполните действия, описанные в одной из следующих статей, чтобы создать ее в портал Azure или с помощью командной строки:

    Использование портала для создания приложения Azure AD и субъекта-службы, которые могут получить доступ к ресурсам

    Use Azure PowerShell to create a service principal with a certificate (Использование Azure PowerShell для создания субъекта-службы с сертификатом)

Шаг 3. Создание секрета для регистрации приложения

Секрет будет использоваться вместе с приложение Azure Id/ClientId при запросе маркера доступа для отправки push-уведомлений.

Секрет приложения AAD

Перейдите к сертификатам и секретам и выберите новый секрет клиента.

Внимание

Убедитесь, что вы скопируете секрет после создания и сохраните его в безопасном расположении, например Azure Key Vault. Он будет доступен только один раз сразу после создания.

Шаг 4. Сопоставление имени семейства пакетов приложения с его приложение Azure Id

Если приложение упаковано (в том числе упаковано с внешним расположением), этот поток можно использовать для сопоставления имени семейства пакетов приложения (PFN) и его приложение Azure Id.

Если приложение является упакованным приложением Win32, создайте запрос сопоставления имен семейства пакетов (PFN), отправив Win_App_SDK_Push@microsoft.com сообщение электронной почты с строкой темы "Запрос на сопоставление push-уведомлений пакета SDK для приложений Windows" и текст "PFN: [ваш PFN]", AppId: [your APPId], ObjectId: [your ObjectId]. Запросы на сопоставление выполняются еженедельно. Вы получите уведомление после завершения запроса на сопоставление.

Настройка приложения для получения push-уведомлений

Шаг 1. Добавление объявлений пространства имен

Добавьте пространство имен для push-уведомлений Microsoft.Windows.PushNotificationsпакета SDK для приложений Windows.

#include <winrt/Microsoft.Windows.PushNotifications.h>

using namespace winrt::Microsoft::Windows::PushNotifications;

Шаг 2. Добавление активатора COM в манифест приложения

Внимание

Если приложение распаковывается (т. е. отсутствует удостоверение пакета во время выполнения), перейдите к шагу 3. Регистрация и реагирование на push-уведомления при запуске приложения.

Если приложение упаковано (включая упакованное с внешним расположением): откройте package.appxmanifest. Добавьте в элемент следующую <Application> команду. Замените Idзначения Executableи DisplayName значения, относящиеся к вашему приложению.

<!--Packaged apps only-->
<!--package.appxmanifest-->

<Package
  ...
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Register COM activator-->    
        <com:Extension Category="windows.comServer">
          <com:ComServer>
              <com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----WindowsAppRuntimePushServer:">
                <com:Class Id="[Your app's Azure AppId]" DisplayName="Windows App SDK Push" />
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>
    
      </Extensions>
    </Application>
  </Applications>
 </Package>    

Шаг 3. Регистрация и реагирование на push-уведомления при запуске приложения

Обновите метод приложения main() , чтобы добавить следующее:

  1. Зарегистрируйте приложение для получения push-уведомлений, вызвав PushNotificationManager::D efault(). Register().
  2. Проверьте источник запроса активации, вызвав AppInstance::GetCurrent(). GetActivatedEventArgs(). Если активация была активирована из push-уведомления, ответьте на основе полезных данных уведомления.

Внимание

Необходимо вызвать PushNotificationManager::D efault(). Зарегистрируйтесь перед вызовом AppInstance.GetCurrent.GetActivatedEventArgs.

Следующий пример представлен в примере упаковаемого приложения на сайте GitHub.

// cpp-console.cpp
#include "pch.h"
#include <iostream>
#include <winrt/Microsoft.Windows.PushNotifications.h>
#include <winrt/Microsoft.Windows.AppLifecycle.h>
#include <winrt/Windows.Foundation.h>
#include <wil/result.h>
#include <wil/cppwinrt.h>


using namespace winrt;
using namespace Windows::Foundation;

using namespace winrt::Microsoft::Windows::PushNotifications;
using namespace winrt::Microsoft::Windows::AppLifecycle;

winrt::guid remoteId{ "7edfab6c-25ae-4678-b406-d1848f97919a" }; // Replace this with your own Azure ObjectId



void SubscribeForegroundEventHandler()
{
    winrt::event_token token{ PushNotificationManager::Default().PushReceived([](auto const&, PushNotificationReceivedEventArgs const& args)
    {
        auto payload{ args.Payload() };

        std::string payloadString(payload.begin(), payload.end());
        std::cout << "\nPush notification content received in the FOREGROUND: " << payloadString << std::endl;
    }) };
}

int main()
{
    // Setup an event handler, so we can receive notifications in the foreground while the app is running.
    SubscribeForegroundEventHandler();

    PushNotificationManager::Default().Register();

    auto args{ AppInstance::GetCurrent().GetActivatedEventArgs() };
    switch (args.Kind())
    {
        // When it is launched normally (by the users, or from the debugger), the sample requests a WNS Channel URI and
        // displays it, then waits for notifications. This user can take a copy of the WNS Channel URI and use it to send
        // notifications to the sample
        case ExtendedActivationKind::Launch:
        {
            // Checks to see if push notifications are supported. Certain self-contained apps may not support push notifications by design
            if (PushNotificationManager::IsSupported())
            {
                // Request a WNS Channel URI which can be passed off to an external app to send notifications to.
                // The WNS Channel URI uniquely identifies this app for this user and device.
                PushNotificationChannel channel{ RequestChannel() };
                if (!channel)
                {
                    std::cout << "\nThere was an error obtaining the WNS Channel URI" << std::endl;
    
                    if (remoteId == winrt::guid { "00000000-0000-0000-0000-000000000000" })
                    {
                        std::cout << "\nThe ObjectID has not been set. Refer to the readme file accompanying this sample\nfor the instructions on how to obtain and setup an ObjectID" << std::endl;
                    }
                }
    
                std::cout << "\nPress 'Enter' at any time to exit App." << std::endl;
                std::cin.ignore();
            }
            else
            {
                // App implements its own custom socket here to receive messages from the cloud since Push APIs are unsupported.
            }
        }
        break;

        // When it is activated from a push notification, the sample only displays the notification.
        // It doesn’t register for foreground activation of perform any other actions
        // because background activation is meant to let app perform only small tasks in order to preserve battery life.
        case ExtendedActivationKind::Push:
        {
            PushNotificationReceivedEventArgs pushArgs{ args.Data().as<PushNotificationReceivedEventArgs>() };

            // Call GetDeferral to ensure that code runs in low power
            auto deferral{ pushArgs.GetDeferral() };

            auto payload{ pushArgs.Payload() } ;

            // Do stuff to process the raw notification payload
            std::string payloadString(payload.begin(), payload.end());
            std::cout << "\nPush notification content received in the BACKGROUND: " << payloadString.c_str() << std::endl;
            std::cout << "\nPress 'Enter' to exit the App." << std::endl;

            // Call Complete on the deferral when finished processing the payload.
            // This removes the override that kept the app running even when the system was in a low power mode.
            deferral.Complete();
            std::cin.ignore();
        }
        break;

        default:
            std::cout << "\nUnexpected activation type" << std::endl;
            std::cout << "\nPress 'Enter' to exit the App." << std::endl;
            std::cin.ignore();
            break;
    }

    // We do not call PushNotificationManager::UnregisterActivator
    // because then we wouldn't be able to receive background activations, once the app has closed.
    // Call UnregisterActivator once you don't want to receive push notifications anymore.
}

Шаг 4. Запрос URI канала WNS и регистрация его с помощью сервера WNS

URI канала WNS — это конечные точки HTTP для отправки push-уведомлений. Каждый клиент должен запросить URI канала и зарегистрировать его на сервере WNS для получения push-уведомлений.

Примечание.

Срок действия URI канала WNS истекает через 30 дней.

auto channelOperation{ PushNotificationManager::Default().CreateChannelAsync(winrt::guid("[Your app's Azure ObjectID]")) };

PushNotificationManager попытается создать универсальный код ресурса (URI) канала, повторно выполняя повторную попытку не более 15 минут. Создайте обработчик событий для ожидания завершения вызова. После завершения вызова, если он был успешным, зарегистрируйте URI на сервере WNS.

// cpp-console.cpp

winrt::Windows::Foundation::IAsyncOperation<PushNotificationChannel> RequestChannelAsync()
{
    // To obtain an AAD RemoteIdentifier for your app,
    // follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
    auto channelOperation = PushNotificationManager::Default().CreateChannelAsync(remoteId);

    // Setup the inprogress event handler
    channelOperation.Progress(
        [](auto&& sender, auto&& args)
        {
            if (args.status == PushNotificationChannelStatus::InProgress)
            {
                // This is basically a noop since it isn't really an error state
                std::cout << "Channel request is in progress." << std::endl << std::endl;
            }
            else if (args.status == PushNotificationChannelStatus::InProgressRetry)
            {
                LOG_HR_MSG(
                    args.extendedError,
                    "The channel request is in back-off retry mode because of a retryable error! Expect delays in acquiring it. RetryCount = %d",
                    args.retryCount);
            }
        });

    auto result = co_await channelOperation;

    if (result.Status() == PushNotificationChannelStatus::CompletedSuccess)
    {
        auto channelUri = result.Channel().Uri();

        std::cout << "channelUri: " << winrt::to_string(channelUri.ToString()) << std::endl << std::endl;

        auto channelExpiry = result.Channel().ExpirationTime();

        // Caller's responsibility to keep the channel alive
        co_return result.Channel();
    }
    else if (result.Status() == PushNotificationChannelStatus::CompletedFailure)
    {
        LOG_HR_MSG(result.ExtendedError(), "We hit a critical non-retryable error with channel request!");
        co_return nullptr;
    }
    else
    {
        LOG_HR_MSG(result.ExtendedError(), "Some other failure occurred.");
        co_return nullptr;
    }

};

PushNotificationChannel RequestChannel()
{
    auto task = RequestChannelAsync();
    if (task.wait_for(std::chrono::seconds(300)) != AsyncStatus::Completed)
    {
        task.Cancel();
        return nullptr;
    }

    auto result = task.GetResults();
    return result;
}

Шаг 5. Создание и установка приложения

Используйте Visual Studio для сборки и установки приложения. Щелкните правой кнопкой мыши файл решения в Обозреватель решений и выберите "Развернуть". Visual Studio создаст приложение и установит его на компьютере. Приложение можно запустить, запустив его с помощью меню "Пуск" или отладчика Visual Studio.

Отправка push-уведомления в приложение

На этом этапе все конфигурации завершено, и сервер WNS может отправлять push-уведомления клиентским приложениям. В следующих шагах дополнительные сведения см. в заголовках запросов и ответов сервера push-уведомлений.

Шаг 1. Запрос маркера доступа

Чтобы отправить push-уведомление, сервер WNS сначала должен запросить маркер доступа. Отправьте HTTP-запрос POST с помощью Azure TenantId, приложение Azure Id и секрета. Сведения о получении Идентификатора клиента Azure и приложение Azure Id см. в статье Get tenant and app ID values for вход.

Пример HTTP-запроса:

POST /{tenantID}/oauth2/v2.0/token Http/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 160

grant_type=client_credentials&client_id=<Azure_App_Registration_AppId_Here>&client_secret=<Azure_App_Registration_Secret_Here>&scope=https://wns.windows.com/.default/

Пример запроса на C#:

//Sample C# Access token request
var client = new RestClient("https://login.microsoftonline.com/{tenantID}/oauth2/v2.0");
var request = new RestRequest("/token", Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "[Your app's Azure AppId]");
request.AddParameter("client_secret", "[Your app's secret]");
request.AddParameter("scope", "https://wns.windows.com/.default");
RestResponse response = await client.ExecutePostAsync(request);
Console.WriteLine(response.Content);

Если запрос выполнен успешно, вы получите ответ, содержащий маркер в поле access_token .

{
    "token_type":"Bearer",
    "expires_in":"86399",
    "ext_expires_in":"86399",
    "expires_on":"1653771789",
    "not_before":"1653685089",
    "access_token":"[your access token]"
}

Шаг 2. Отправка необработанного уведомления

Создайте HTTP-запрос POST, содержащий маркер доступа, полученный на предыдущем шаге, и содержимое push-уведомления, которое вы хотите отправить. Содержимое push-уведомления будет доставлено в приложение.

POST /?token=[The token query string parameter from your channel URL. E.g. AwYAAABa5cJ3...] HTTP/1.1
Host: dm3p.notify.windows.com
Content-Type: application/octet-stream
X-WNS-Type: wns/raw
Authorization: Bearer [your access token]
Content-Length: 46

{ Sync: "Hello from the Contoso App Service" }
var client = new RestClient("[Your channel URL. E.g. https://wns2-by3p.notify.windows.com/?token=AwYAAABa5cJ3...]");
var request = new RestRequest();
request.Method = Method.Post; 
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("X-WNS-Type", "wns/raw");
request.AddHeader("Authorization", "Bearer [your access token]");
request.AddBody("Notification body");
RestResponse response = await client.ExecutePostAsync(request);");

Шаг 3. Отправка уведомления об облачном приложении

Если вы заинтересованы только в отправке необработанных уведомлений, игнорируйте этот шаг. Чтобы отправить уведомление из облака, также известное всплывающее уведомление, сначала выполните краткое руководство. Уведомления приложений в пакете SDK для приложений Для Windows. Уведомления приложений могут отправляться (отправляться из облака) или отправляться локально. Отправка уведомления о облачном приложении похожа на отправку необработанного уведомления на шаге 2, за исключением заголовка X-WNS-Type , content-Type istext/xmltoast, и содержимое содержит полезные данные XML уведомления приложения. Дополнительные сведения о создании полезных данных XML см . в xml-схеме уведомлений.

Создайте HTTP-запрос POST, содержащий маркер доступа и содержимое уведомления о облачном приложении, которое вы хотите отправить. Содержимое push-уведомления будет доставлено в приложение.

POST /?token=AwYAAAB%2fQAhYEiAESPobjHzQcwGCTjHu%2f%2fP3CCNDcyfyvgbK5xD3kztniW%2bjba1b3aSSun58SA326GMxuzZooJYwtpgzL9AusPDES2alyQ8CHvW94cO5VuxxLDVzrSzdO1ZVgm%2bNSB9BAzOASvHqkMHQhsDy HTTP/1.1
Host: dm3p.notify.windows.com
Content-Type: text/xml
X-WNS-Type: wns/toast
Authorization: Bearer [your access token]
Content-Length: 180

<toast><visual><binding template="ToastGeneric"><text>Example cloud toast notification</text><text>This is an example cloud notification using XML</text></binding></visual></toast>
var client = new RestClient("https://dm3p.notify.windows.com/?token=AwYAAAB%2fQAhYEiAESPobjHzQcwGCTjHu%2f%2fP3CCNDcyfyvgbK5xD3kztniW%2bjba1b3aSSun58SA326GMxuzZooJYwtpgzL9AusPDES2alyQ8CHvW94cO5VuxxLDVzrSzdO1ZVgm%2bNSB9BAzOASvHqkMHQhsDy");
client.Timeout = -1;

var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "text/xml");
request.AddHeader("X-WNS-Type", "wns/toast");
request.AddHeader("Authorization", "Bearer <AccessToken>");
request.AddParameter("text/xml", "<toast><visual><binding template=\"ToastGeneric\"><text>Example cloud toast notification</text><text>This is an example cloud notification using XML</text></binding></visual></toast>",  ParameterType.RequestBody);
Console.WriteLine(response.Content);

Ресурсы