Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом кратком руководстве вы создадите классическое приложение Windows, которое отправляет и получает push-уведомления с помощью пакета SDK для приложений Windows.
Prerequisites
- Начало разработки приложений Windows
- Создайте новый проект, использующий пакет SDK для приложений Windows, или используйте пакет SDK для приложений Windows в существующем проекте.
- Для использования push-уведомлений windows App SDK требуется учетной записи Azure.
- Обзор push-уведомлений
Пример приложения
В этом кратком руководстве описывается добавление поддержки push-уведомлений в приложение в пакете SDK для приложений Windows 1.7. См. аналогичный код этого краткого руководства в примерах приложений, найденных на сайте GitHub. Обязательно ознакомьтесь с ветвью с предпочитаемой версией пакета SDK для приложений Windows для примеров, которые лучше всего соответствуют вашему проекту.
Вы также можете найти примеры для каждой версии пакета SDK для приложений Windows, выбрав ветвь версии в репозитории примеров.
Справочник по API
Справочную документацию по API для push-уведомлений можно найти в пространстве имен Microsoft.Windows.PushNotifications, см.
Настройка идентификатора приложения в Azure Active Directory (AAD)
Push-уведомления в Windows App SDK используют идентификацию из Azure Active Directory (AAD). Учетные данные Azure необходимы при запросе URI канала WNS и при запросе маркеров доступа для отправки push-уведомлений. Примечание: Мы НЕ поддерживаем push-уведомления пакета Windows App SDK через Центр партнеров Майкрософт.
Шаг 1. Создание регистрации приложения AAD
Войдите в учетную запись Azure и создайте новый ресурс регистрации приложения AAD . Выберите Новая регистрация.
Шаг 2. Укажите имя и выберите параметр многоарендности
Введите имя приложения
Для push-уведомлений требуется параметр с несколькими клиентами, поэтому выберите это.
- Дополнительные сведения об арендаторах см. в разделе Кто может войти в приложение?.
Нажмите кнопку Зарегистрировать.
Запишите идентификатор приложения (клиента) , так как это ваш Azure AppId , который вы будете использовать во время регистрации активации и запроса токена доступа.
Запишите ваш идентификаторкаталога
(клиента), так как это ваш Azure TenantId , который вы будете использовать при запросе токена доступа. Important
запишите идентификаторклиент регистрации приложений AAD приложения (клиента) иидентификатор каталога(клиента). Запишите ваш идентификатор объекта , так как это ваш Azure ObjectId, который вы будете использовать при запросе канала. Обратите внимание, что это НЕ идентификатор объекта, указанный на странице Essentials . Вместо этого, чтобы найти правильный идентификатор объекта , щелкните название приложения в поле управляемого приложения в локальном каталоге на странице Essentials.
Note
Для получения идентификатора объекта требуется субъекта-службы; если ни один из них не связан с вашим приложением, выполните действия, описанные в одной из следующих статей, чтобы создать его на портале Azure или с помощью командной строки.
Используйте Azure PowerShell для создания учетной записи службы с помощью сертификата
Шаг 3. Создание секрета для регистрации приложения
Ваш секрет будет использоваться вместе с Azure AppId/ClientId, когда вы запрашиваете токен доступа, чтобы отправлять push-уведомления.
Перейдите к сертификатам и секретам и выберите новый секрет клиента.
Important
Убедитесь, что вы скопируете секрет после создания и сохраните его в безопасном расположении, например Azure Key Vault. Он будет доступен только один раз сразу после создания.
Шаг 4. Сопоставьте имя семейства пакетов вашего приложения с его Azure AppId
Если ваше приложение упаковано (в том числе упаковано с внешним расположением), можно использовать этот процесс для определения имени семейства пакетов приложения (PFN) и его идентификатора приложения Azure.
Если приложение является упакованным приложением Win32, создайте запрос сопоставления имен семейства пакетов (PFN), отправив [email protected] сообщение электронной почты с строкой темы "Запрос на сопоставление push-уведомлений пакета SDK для приложений Windows" и текст "PFN: [ваш PFN]", AppId: [your APPId], ObjectId: [your ObjectId]. Запросы на сопоставление выполняются еженедельно. Вы получите уведомление после завершения запроса на сопоставление.
После получения идентификатора приложения Azure, ObjectId и секрета вы можете добавить эти учетные данные в пример кода ниже.
Настройка приложения для получения push-уведомлений
Шаг 1. Добавление пакета SDK для приложений Windows и необходимых пакетов NuGet
Затем щелкните правой кнопкой мыши решение в обозревателе решений и выберите пункт "Управление пакетами NuGet".
В диспетчере пакетов добавьте следующие пакеты:
- Microsoft.WindowsAppSDK (минимальная версия 1.1.0)
- Microsoft.Windows.SDK.BuildTools (минимальная версия 10.0.22000.194)
- Microsoft.Windows.CppWinRT, (минимальная версия 2.0.210930.14)
- Microsoft.Windows.ImplementationLibrary, (минимальная версия 1.0.210930.1)
Если это первый раз, когда вы используете пакет SDK для приложений Windows в проекте и упаковываются с внешним расположением или распаковкой, инициализировать пакет SDK для приложений Windows, добавив в файл проекта следующее свойство:
<!-- your .vcxproj or .proj file -->
<PropertyGroup Label="Globals">
<!-- Other properties -->
<WindowsPackageType>None</WindowsPackageType>
</PropertyGroup>
или используйте API начальной загрузки. Дополнительные сведения см . в статье "Использование среды выполнения ПАКЕТА SDK для приложений Windows", упакованных с внешним расположением или распаковкой .
Note
Если пакет SDK не инициализирован, приложение вызовет System.Runtime.InteropServices.COMException (0x80040154): Class not registered (0x80040154 (REGDB_E_CLASSNOTREG))
и не будет выполняться.
Шаг 2. Добавление пространств имен
Затем добавьте пространство имен для push-уведомлений Microsoft.Windows.PushNotifications
пакета SDK для приложений Windows.
#include <winrt/Microsoft.Windows.PushNotifications.h>
using namespace winrt::Microsoft::Windows::PushNotifications;
Если вы получите ошибку "Не удается найти Microsoft.Windows.PushNotifications", скорее всего, это означает, что файлы заголовков не были созданы. Чтобы устранить проблему, убедитесь, что установлены пакеты выше, закомментируйте инструкции include и using, вызывающие ошибку, и перестроите приложение для создания файлов заголовков. После успешной сборки раскомментируйте инструкции include и using и перестроите проект. Это должно устранить ошибку.
Шаг 3. Добавление активатора COM в манифест приложения
Important
Если приложение распаковывается (т. е. отсутствует удостоверение пакета во время выполнения), перейдите к шагу 4. Регистрация и реагирование на 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>
Note
Пример завершенного класса C++ для этого примера можно найти после шага 5. Шаги 4 и 5 предоставляют пошаговые инструкции по добавлению каждого элемента в последнем примере.
Шаг 4. Регистрация и реагирование на push-уведомления при запуске приложения
Обновите метод приложения main()
, чтобы добавить следующее:
- Зарегистрируйте приложение для получения push-уведомлений, вызвав PushNotificationManager::Default().Register().
- Проверьте источник запроса активации, вызвав AppInstance::GetCurrent().GetActivatedEventArgs(). Если активация была вызвана push-уведомлением, ответьте, учитывая данные уведомления.
Important
Необходимо вызвать PushNotificationManager::D efault(). Зарегистрируйте перед вызовом AppInstance.GetCurrent.GetActivatedEventArgs.
Добавление обработчиков событий переднего плана
Чтобы обработать событие на переднем плане, зарегистрируйте обработчик для PushNotificationManager.PushReceived.
Important
Кроме того, перед вызовом PushNotificationManager.Register() необходимо зарегистрировать любые обработчики событий PushNotificationManager.Register (). В противном случае будет создано следующее исключение среды выполнения:
System.Runtime.InteropServices.COMException: Element not found. Must register event handlers before calling Register().
Добавление проверки PushNotificationManager::IsSupported()
Затем добавьте проверку того, поддерживаются ли API PushNotification в PushNotificationManager.IsSupported(). В противном случае рекомендуется использовать опрос или собственную реализацию пользовательского сокета.
Теперь, когда поддержка push-уведомлений подтверждена, добавьте поведение на основе PushNotificationReceivedEventArgs.
Шаг 5. Запрос URI канала WNS и регистрация его с помощью сервера WNS
URI канала WNS — это конечные точки HTTP для отправки push-уведомлений. Каждый клиент должен запросить URI канала и зарегистрировать его на сервере WNS для получения push-уведомлений.
Note
Срок действия URI канала WNS истекает через 30 дней.
auto channelOperation{ PushNotificationManager::Default().CreateChannelAsync(winrt::guid("[Your app's Azure ObjectID]")) };
Если вы используете код учебника, добавьте здесь идентификатор объекта Azure:
// To obtain an AAD RemoteIdentifier for your app,
// follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
winrt::guid remoteId{ "00000000-0000-0000-0000-000000000000" }; // Replace this with your own Azure ObjectId
PushNotificationManager попытается создать URI канала, повторяя попытку в течение не более чем 15 минут. Создайте обработчик событий для ожидания завершения вызова. После завершения вызова, если он был успешным, зарегистрируйте URI на сервере WNS.
Пример кода
#include <iostream>
#include <winrt/Microsoft.Windows.PushNotifications.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Microsoft.Windows.AppLifecycle.h>
#include <winrt/Windows.ApplicationModel.Background.h>
#include <wil/cppwinrt.h>
#include <wil/result.h>
using namespace winrt::Microsoft::Windows::PushNotifications;
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Windows::AppLifecycle;
// To obtain an AAD RemoteIdentifier for your app,
// follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
winrt::guid remoteId{ "00000000-0000-0000-0000-000000000000" }; // Replace this with your own Azure ObjectId
winrt::Windows::Foundation::IAsyncOperation<PushNotificationChannel> RequestChannelAsync()
{
auto channelOperation = PushNotificationManager::Default().CreateChannelAsync(remoteId);
// Set up the in-progress 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;
}
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;
}) };
std::cout << "Push notification foreground event handler registered." << std::endl;
}
int main()
{
// Set up an event handler, so we can receive notifications in the foreground while the app is running.
// You must register notification event handlers before calling Register(). Otherwise, the following runtime
// exception will be thrown: System.Runtime.InteropServices.COMException: 'Element not found. Must register
// event handlers before calling Register().'
SubscribeForegroundEventHandler();
// Register the app for push notifications.
PushNotificationManager::Default().Register();
auto args{ AppInstance::GetCurrent().GetActivatedEventArgs() };
switch (args.Kind())
{
case ExtendedActivationKind::Launch:
{
std::cout << "App launched by user or from the debugger." << std::endl;
if (PushNotificationManager::IsSupported())
{
std::cout << "Push notifications are supported on this device." << std::endl;
// 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
{
std::cout << "Push notifications are NOT supported on this device." << std::endl;
std::cout << "App implements its own custom socket here to receive messages from the cloud since Push APIs are unsupported." << std::endl;
std::cin.ignore();
}
}
break;
case ExtendedActivationKind::Push:
{
std::cout << "App activated via push notification." << std::endl;
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;
}
}
Шаг 6. Создание и установка приложения
Используйте Visual Studio для сборки и установки приложения. Щелкните правой кнопкой мыши файл решения в обозревателе решений и выберите "Развернуть". Visual Studio создаст приложение и установит его на компьютере. Приложение можно запустить, запустив его с помощью меню "Пуск" или отладчика Visual Studio.
Консоль кода учебника будет выглядеть следующим образом:
Для отправки push-уведомления в приложение потребуется маркер.
Отправка push-уведомления в приложение
На этом этапе все конфигурации завершено, и сервер WNS может отправлять push-уведомления клиентским приложениям. В следующих шага х дополнительные сведения см. в
Шаг 1: Запрос токена доступа
Чтобы отправить push-уведомление, сервер WNS сначала должен запросить маркер доступа. Отправьте HTTP-запрос POST с вашим Azure TenantId, Azure AppId и секретным ключом. Сведения о получении Идентификатора клиента (TenantId) Azure и Идентификатора приложения (AppId) Azure см. в разделе Получение значений идентификатора клиента и приложения для входа.
Пример 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. Отправка уведомления об облачном приложении
Если вы заинтересованы только в отправке необработанных уведомлений, игнорируйте этот шаг. Чтобы отправить уведомление приложения из облака, также известное как push-уведомление или всплывающее уведомление, сначала выполните Краткое руководство: Уведомления приложений в Windows App SDK. Уведомления приложений могут отправляться (отправляться из облака) или отправляться локально. Отправка уведомления об использовании облачного приложения аналогична отправке необработанного уведомления в
Создайте 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);
Resources
Windows developer