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에서 다음을 추가합니다.
- xmlns:com 선언
- xmlns:desktop 선언
- IgnorableNamespaces 특성에서 4단계의 GUID를 사용한 COM 활성자에 대한 com, desktop
- 선택한 신규 GUID를 사용한 알림 활성자 CLSID를 선언하는 windows.toastNotificationActivation에 대한 desktop:Extension
- 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)에서 다음과 같이 코드를 수정합니다.
- 앱 수준 정의 및 잡기
DispatcherQueue ToastNotificationManagerCompat.OnActivated이벤트 등록- 창 시작/활성화 코드를 전용
LaunchAndBringToForegroundIfNeeded메서드로 리팩터링하여 여러 위치에서 호출할 수 있습니다. - true를 반환하는 경우
ToastNotificationManagerCompat.WasCurrentProcessToastActivated()창을 시작하지 마세요(해당 메서드가 trueOnActivated이면 다음에 이벤트가 호출되고 이벤트 콜백 내에 창을 표시하도록 선택할 수 있음). - 창 표시 또는 UI 업데이트와 같은 UI 관련 코드를 실행하기 전에 앱 또는 창 디스패처로 디스패치해야 합니다
ToastNotificationManagerCompat.OnActivated. - 알림 활성화를 처리한 이전 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);
}
}