クイックスタート: Windows App SDK のプッシュ通知
このクイックスタートでは、Windows アプリ SDK を使用してプッシュ通知を送受信するデスクトップ Windows アプリケーションを作成します。
前提条件
- WinUI の概要
- Windows アプリ SDK を使う新しいプロジェクトを作成するか、既存のプロジェクトで Windows アプリ SDK を使います
- Windows アプリ SDK のプッシュ通知を使うには、Azure アカウントが必要です。
- 「プッシュ通知の概要」を読み取りください。
サンプル アプリ
このクイックスタートでは、アプリにプッシュ通知のサポートを追加する手順について説明します。 このクイックスタートのコード例は、GitHubにあるサンプル アプリのコンテキストで参照してください。
API リファレンス
プッシュ通知の API リファレンス ドキュメントについては、「Microsoft.Windows.PushNotifications 名前空間」を参照してください。
Azure Active Directory (AAD) でアプリの ID を構成する
Windows アプリ SDK のプッシュ通知では、Azure Active Directory (AAD) の ID が使用されます。 Azure 資格情報は、WNS チャネル URI を要求するとき、およびプッシュ通知を送信するためにアクセス トークンを要求するときに必要です。 注: Microsoft パートナー センターでの Windows アプリ SDK プッシュ通知の使用はサポートされていません。
手順 1: AAD アプリ登録を作成する
Azure アカウントにログインし、新しい AAD アプリ登録リソースを作成します。 [新規登録] を選択します。
手順 2: 名前を指定し、マルチテナント オプションを選ぶ
アプリケーションの名前を指定します。
プッシュ通知にはマルチテナント オプションが必須なので、選びます。
- テナントの詳細については、「アプリケーションにサインインできるユーザー」を参照してください。
[登録] を選択します
アプリケーション (クライアント) ID は、アクティブ化の登録とアクセス トークンの要求時に使用する Azure AppId であるため、メモしておきます。
ディレクトリ (テナント) ID は、アクセス トークンを要求するときに使用する Azure TenantId であるため、メモしておきます。
重要
アプリケーション (クライアント) ID とディレクトリ (テナント) ID をメモします。
オブジェクト ID は、チャネル要求を要求するときに使用する Azure ObjectId であるため、メモしておきます。 これは、[要点] ページに一覧表示されているオブジェクト ID ではないことに注意してください。 代わりに、正しいオブジェクト ID を見つけるには、[要点] ページの [ローカル ディレクトリ内のマネージド アプリケーション] フィールドでアプリ名をクリックします。
Note
オブジェクト ID を取得するにはサービス プリンシパルが必要であり、アプリに関連付けられているものがない場合は、次のいずれかの記事の手順に従って、Azure portal またはコマンド ラインを使用して作成します。
手順 3: アプリ登録のシークレットを作成する
シークレットは、プッシュ通知を送信するためのアクセス トークンを要求するときに、Azure AppId/ClientId と共に使用されます。
認定資格証 & シークレット に移動し、新しいクライアント シークレットを選択します。
重要
作成したシークレットは必ずコピーして、Azure Key Vault などの安全な場所に格納してください。 確認できるのは、作成直後の一度だけです。
手順 4: アプリのパッケージ ファミリ名を Azure AppId にマップする
アプリがパッケージ化されている場合 (外部の場所でパッケージ化されている場合を含む)、このフローを使用して、アプリのパッケージ ファミリ名 (PFN) とその Azure アプリId をマップできます。
アプリがパッケージ化された Win32 アプリの場合は、件名に "Windows アプリ SDK Push Notifications Mapping Request" と本文 "PFN: [your PFN]"、AppId: [your APPId]、ObjectId: [your ObjectId]を電子 Win_App_SDK_Push@microsoft.comメールで送信して、パッケージ ファミリ名 (PFN) マッピング要求を作成します。 マッピング要求は週単位で完了します。 マッピング要求が完了すると、通知されます。
プッシュ通知を受け取るようにアプリを構成する
ステップ 1: 名前空間の宣言を追加する
Windows アプリ SDK プッシュ通知 Microsoft.Windows.PushNotifications
の名前空間を追加します。
#include <winrt/Microsoft.Windows.PushNotifications.h>
using namespace winrt::Microsoft::Windows::PushNotifications;
手順 2: COM アクティベーターをアプリ マニフェストに追加する
重要
アプリがパッケージ化されていない場合 (つまり、実行時にパッケージ ID がない場合) は、「手順 3: アプリの起動時にプッシュ通知に登録して応答する」に進んでください。
アプリがパッケージ化されている場合 (外部の場所でパッケージ化されている場合を含む): 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: アプリの起動時にプッシュ通知を登録して応答する
アプリの main()
メソッドを更新して、以下を追加します。
- PushNotificationManager::D efault() を呼び出して、プッシュ通知を受信するようにアプリを登録します。Register()です。
- AppInstance::GetCurrent().GetActivatedEventArgs() を呼び出して、アクティブ化要求のソースを確認します。 アクティブ化がプッシュ通知からトリガーされた場合は、通知のペイロードに基づいて応答します。
重要
AppInstance.GetCurrent.GetActivatedEventArgs を呼び出す前に、AppNotificationManager::Default().Register を呼び出す必要があります。
次のサンプルは、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: WNS チャネル URI を要求し、WNS サーバーに登録する
WNS チャネル URI は、プッシュ通知を送信するための HTTP エンドポイントです。 プッシュ通知を受信するには、各クライアントがチャネル URI を要求し、それを WNS サーバーに登録する必要があります。
Note
WNS チャネル URI は 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 デバッガーから起動します。
アプリにプッシュ通知を送信する
この時点で、すべての構成が完了し、WNS サーバーはクライアント アプリにプッシュ通知を送信できます。 次の手順では、プッシュ通知サーバーの要求ヘッダーと応答ヘッダーを参照してください。
手順 1: アクセス トークンを要求する
プッシュ通知を送信するには、まず WNS サーバーがアクセス トークンを要求する必要があります。 Azure TenantId、Azure AppId、シークレットを含む HTTP POST 要求を送信します。 Azure TenantId と Azure AppId の取得については、「サインイン用のテナント ID とアプリ ID の値を取得する」を参照してください。
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 要求を作成します。 プッシュ通知の内容がアプリに配信されます。
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: クラウドソースのアプリ通知を送信する
直接通知の送信のみに関心がある場合は、この手順を無視してください。 クラウドソースのアプリ通知 (プッシュ トースト通知とも呼ばれます) を送信するには、まず Windows アプリ SDK の「クイック スタート: アプリ通知」に従います。 アプリの通知は、プッシュ (クラウドから送信) またはローカルで送信できます。 クラウドソースのアプリ通知の送信は、手順 2 の直接通知の送信と似ていますが、X-WNS-Type ヘッダーが toast
、Content-Type が text/xml
で、コンテンツにアプリ通知 XML ペイロードが含まれている点が異なります。 XMLペイロードの構築方法の詳細は、通知XMLスキーマを参照してください。
アクセス トークンと、送信するクラウド ソースのアプリ通知の内容を含む HTTP POST 要求を作成します。 プッシュ通知の内容がアプリに配信されます。
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);
リソース
Windows developer