UWP에서 WinUI 3 마이그레이션으로 알림 메시지

알림 메시지를 UWP에서 WinUI 3으로 마이그레이션할 때 유일한 차이점은 알림 활성화를 처리하는 것입니다. 알림 메시지 보내기 및 관리는 동일하게 유지됩니다.

정품 인증 차이점

범주 UWP WinUI 3
포그라운드 활성화 진입점 OnActivated 내부 App.xaml.cs 메서드가 호출됩니다. 이벤트 구독 ToastNotificationManagerCompat.OnActivated (또는 C++용 COM 클래스)
백그라운드 활성화 진입점 백그라운드 작업으로 별도로 처리됨 동일한 ToastNotificationManagerCompat.OnActivated 이벤트(또는 C++용 COM 클래스)를 통해 도착합니다.
창 활성화 포그라운드 활성화가 발생하면 창이 자동으로 포그라운드로 전환됩니다. 원하는 경우 창을 포그라운드로 가져와야 합니다.

C# 앱에 대한 마이그레이션

1단계: NuGet 라이브러리 설치

Visual Studio 솔루션 내에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 "NuGet 패키지 관리..."를 클릭한 후 NuGet 패키지 버전 7.0 이상을 검색하여 설치합니다.

이 패키지는 API를 ToastNotificationManagerCompat 추가합니다.

2단계: 매니페스트 업데이트

Package.appxmanifest에서 다음을 추가합니다.

  1. xmlns:com 선언
  2. xmlns:desktop 선언
  3. IgnorableNamespaces 특성에서 4단계의 GUID를 사용한 COM 활성자에 대한 com, desktop
  4. 선택한 신규 GUID를 사용한 알림 활성자 CLSID를 선언하는 windows.toastNotificationActivation에 대한 desktop:Extension
  5. MSIX만 해당: 4단계에서 GUID를 사용하는 COM 활성자의 com:Extension 알림에서 실행을 알 수 있도록 Arguments="-ToastActivated"를 포함해야 합니다.

Package.appxmanifest

<!--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 toast 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="-ToastActivated" DisplayName="Toast activator">
              <com:Class Id="replaced-with-your-guid-C173E6ADF0C3" DisplayName="Toast activator"/>
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>

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

3단계: 활성화 처리

앱의 시작 코드 (일반적으로 App.xaml.cs)에서 다음과 같이 코드를 수정합니다.

  1. 앱 수준 정의 및 잡기 DispatcherQueue
  2. ToastNotificationManagerCompat.OnActivated 이벤트 등록
  3. 창 시작/활성화 코드를 전용 LaunchAndBringToForegroundIfNeeded 메서드로 리팩터링하여 여러 위치에서 호출할 수 있습니다.
  4. true를 반환하는 경우 ToastNotificationManagerCompat.WasCurrentProcessToastActivated() 창을 시작하지 마세요(해당 메서드가 true OnActivated 이면 다음에 이벤트가 호출되고 이벤트 콜백 내에 창을 표시하도록 선택할 수 있음).
  5. 창 표시 또는 UI 업데이트와 같은 UI 관련 코드를 실행하기 전에 앱 또는 창 디스패처로 디스패치해야 합니다 ToastNotificationManagerCompat.OnActivated.
  6. 알림 활성화를 처리한 이전 UWP 코드를 새 ToastNotificationManagerCompat.OnActivated 이벤트 처리기로 마이그레이션하고 백그라운드 작업 알림 활성화 코드를 새 ToastNotificationManagerCompat.OnActivated 이벤트 처리기로 마이그레이션합니다.

마이그레이션된 App.xaml.cs

public static DispatcherQueue DispatcherQueue { get; private set; }

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    // Get the app-level dispatcher
    DispatcherQueue = global::Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

    // Register for toast activation. Requires Microsoft.Toolkit.Uwp.Notifications NuGet package version 7.0 or greater
    ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompat_OnActivated;

    // If we weren't launched by a toast, launch our window like normal.
    // Otherwise if launched by a toast, our OnActivated callback will be triggered
    if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
    {
        LaunchAndBringToForegroundIfNeeded();
    }
}

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 toast, it doesn't
        // activate the window correctly
        WindowHelper.ShowWindow(m_window);
    }
    else
    {
        WindowHelper.ShowWindow(m_window);
    }
}

private void ToastNotificationManagerCompat_OnActivated(ToastNotificationActivatedEventArgsCompat e)
{
    // Use the dispatcher from the window if present, otherwise the app dispatcher
    var dispatcherQueue = m_window?.DispatcherQueue ?? App.DispatcherQueue;

    dispatcherQueue.TryEnqueue(delegate
    {
        var args = ToastArguments.Parse(e.Argument);

        switch (args["action"])
        {
            // Send a background message
            case "sendMessage":
                string message = e.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);
    }
}