UWP から WinUI 3 への移行に関するアプリ通知

UWP から WinUI 3 にアプリ通知コードを移行する場合の唯一の違いは、通知のアクティブ化を処理することです。 アプリ通知の送信と管理はまったく同じです。

Note

"トースト通知" という用語は、"アプリ通知" に置き換えられます。 これらの用語はどちらも Windows の同じ機能を指していますが、時間の経過と共に、ドキュメントでの "トースト通知" の使用を段階的に廃止します。

Note

一部の情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

アクティブ化の違い

カテゴリ UWP WinUI 3
フォアグラウンド アクティブ化エントリ ポイント OnActivatedApp.xaml.cs内のメソッドが呼び出されます OnLaunchedApp.xaml.cs内のメソッドが呼び出されます。
バックグラウンド アクティブ化エントリ ポイント バックグラウンド タスクとして個別に処理される フォアグラウンド のアクティブ化と同じです。 OnLaunchedApp.xaml.cs内のメソッドが呼び出されます。 GetActivatedEventArgs を使用して、アプリを完全に起動するか、タスクを処理して終了するかを判断します。
ウィンドウのアクティブ化 フォアグラウンドのアクティブ化が発生すると、ウィンドウが自動的にフォアグラウンドに移動します 必要に応じて、ウィンドウを前面に移動する必要があります

C# アプリの移行

手順 1: NuGet ライブラリをインストールする

WinUI 3 アプリの場合は、 AppNotificationManager クラスを使用して通知のアクティブ化を処理します。 このクラスは、WinUI 3 Visual Studio プロジェクト テンプレートに既定で含まれている Microsoft.WindowsAppSDK Nuget パッケージによって提供されます。

手順 2: マニフェストを更新する

Package.appxmanifestに次を追加します。

  1. xmlns:com の 宣言
  2. xmlns:desktop の 宣言
  3. IgnorableNamespaces 属性では、comデスクトップ
  4. トースト アクティベーター CLSID (任意の新しい GUID を使用) を宣言するための、windows.toastNotificationActivationdesktop:Extension
  5. MSIX のみ: COM アクティベーターの com:Extension (手順 4 の GUID を使用)。 通知から起動されたことがわかるように、必ず Arguments="----AppNotificationActivated:" を含めます
<!--Add these namespaces-->
<Package
  ...
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  IgnorableNamespaces="... com desktop">
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Specify which CLSID to activate when app notification clicked-->
        <desktop:Extension Category="windows.toastNotificationActivation">
          <desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" /> 
        </desktop:Extension>

        <!--Register COM CLSID LocalServer32 registry key-->
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:ExeServer Executable="YourProject.exe" Arguments="----AppNotificationActivated:" DisplayName="App notification activator">
              <com:Class Id="replaced-with-your-guid-C173E6ADF0C3" DisplayName="App notification activator"/>
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>

      </Extensions>
    </Application>
  </Applications>
 </Package>

手順 3: アクティブ化を処理する

アプリのスタートアップ コード (通常はApp.xaml.cs) で、次の手順に従ってコードを更新します。

  1. OnLaunched で、AppNotificationManager クラスの既定のインスタンスを取得します。
  2. AppNotificationManager.NotificationInvoked イベントに登録します。
  3. Microsoft.Windows.AppNotifications.AppNotificationManager.Register を呼び出して、通知イベントを受信するようにアプリを登録します。 NotificationInvoked ハンドラーを登録した後で、このメソッドを呼び出すことが重要です。
  4. ウィンドウの起動/アクティブ化コードを専用の LaunchAndBringToForegroundIfNeeded ヘルパー メソッドにリファクタリングして、複数の場所から呼び出すことができるようにします。
  5. 複数の場所から呼び出すことができるように、 HandleNotification ヘルパー メソッドを作成します。
  6. AppInstance.GetActivatedEventArgsを呼び出し、返されたオブジェクトの AppActivationArguments.Kind プロパティの値ExtendedActivationKind.AppNotification を確認します。
  7. アクティブ化の種類が AppNotification でない場合はLaunchAndBringToForegroundIfNeeded ヘルパー メソッドを呼び出します。
  8. アクティブ化の種類が AppNotification の場合AppActivationArguments.Data プロパティを AppNotificationActivatedEventArgs にキャストし、HandleNotification ヘルパー メソッドに渡します。
  9. ApplicationManager.NotificationInvoked ハンドラーで、HandleNotification ヘルパー メソッドを呼び出します。
  10. HandleNotification ヘルパー メソッド内で、ウィンドウの表示や UI の更新など、UI 関連のコードを実行する前に、必ずアプリまたはウィンドウ ディスパッチャーにディスパッチしてください
  11. アプリ通知のアクティブ化を処理した古い UWP OnActivated コードを新しい HandleNotification ヘルパー メソッドに移行します。

移行されたApp.xaml.cs


protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();

    // To ensure all Notification handling happens in this process instance, register for
    // NotificationInvoked before calling Register(). Without this a new process will
    // be launched to handle the notification.
    AppNotificationManager notificationManager = AppNotificationManager.Default;
    notificationManager.NotificationInvoked += NotificationManager_NotificationInvoked;
    notificationManager.Register();

    var activatedArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
    var activationKind = activatedArgs.Kind;
    if (activationKind != ExtendedActivationKind.AppNotification)
    {
        LaunchAndBringToForegroundIfNeeded();
    } else
    {
        HandleNotification((AppNotificationActivatedEventArgs)activatedArgs.Data);
    }

}

private void LaunchAndBringToForegroundIfNeeded()
{
    if (m_window == null)
    {
        m_window = new MainWindow();
        m_window.Activate();

        // Additionally we show using our helper, since if activated via a app notification, it doesn't
        // activate the window correctly
        WindowHelper.ShowWindow(m_window);
    }
    else
    {
        WindowHelper.ShowWindow(m_window);
    }
}

private void NotificationManager_NotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
{
    HandleNotification(args);
}

private void HandleNotification(AppNotificationActivatedEventArgs args)
{
  // Use the dispatcher from the window if present, otherwise the app dispatcher
  var dispatcherQueue = m_window?.DispatcherQueue ?? DispatcherQueue.GetForCurrentThread();


  dispatcherQueue.TryEnqueue(async delegate
  {

      switch (args.Arguments["action"])
      {
          // Send a background message
          case "sendMessage":
              string message = args.UserInput["textBox"].ToString();
              // TODO: Send it

              // If the UI app isn't open
              if (m_window == null)
              {
                  // Close since we're done
                  Process.GetCurrentProcess().Kill();
              }

              break;

          // View a message
          case "viewMessage":

              // Launch/bring window to foreground
              LaunchAndBringToForegroundIfNeeded();

              // TODO: Open the message
              break;
      }
  });
}

private static class WindowHelper
{
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    public static void ShowWindow(Window window)
    {
        // Bring the window to the foreground... first get the window handle...
        var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

        // Restore window if minimized... requires DLL import above
        ShowWindow(hwnd, 0x00000009);

        // And call SetForegroundWindow... requires DLL import above
        SetForegroundWindow(hwnd);
    }
}

アプリ通知コンテンツの構築

Windows アプリ SDKでは、未加工の xml を使用してアプリ通知コンテンツを作成できますが、Windows Community Toolkit によって提供される ToastContentBuilder クラスに代わる新しい AppNotificationsBuilder API を使用してアプリ通知コンテンツを作成することもできます。 AppNotificationManager.Show を呼び出して、アプリ通知を送信します。 Windows Community Toolkit と App SDK API の混在はお勧めしません。

using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;

...

var builder = new AppNotificationBuilder()
    .AddText("Send a message.")
    .AddTextBox("textBox")
    .AddButton(new AppNotificationButton("Send")
        .AddArgument("action", "sendMessage"));

var notificationManager = AppNotificationManager.Default;
notificationManager.Show(builder.BuildNotification());