共用方式為


通知接聽程式:存取所有通知

通知接聽程式可讓您存取使用者的通知。 智慧型手錶和其他穿戴式裝置可以使用通知接聽程式,將手機的通知傳送至穿戴式裝置。 家庭自動化應用程式可以使用通知接聽程式在收到通知時執行特定動作,例如,有來電時讓燈光閃爍。

重要

需要年度更新版:您必須以 SDK 14393 為目標,並執行組建 14393 或更新版本,才能使用通知接聽程式。

重要的 APIUserNotificationListener 類別UserNotificationChangedTrigger 類別

新增使用者通知功能來啟用接聽程式

若要使用通知接聽程式,您必須將使用者通知接聽程式功能新增至應用程式資訊清單中。

  1. 在 Visual Studio 的 [方案總管] 中,按兩下 Package.appxmanifest 檔案以開啟資訊清單設計工具。
  2. 開啟 [功能] 索引標籤。
  3. 勾選 [使用者通知接聽程式] 功能。

查看是否支援接聽程式

如果您的應用程式支援舊版 Windows 10,您必須使用 ApiInformation 類別 來查看是否支援接聽程式。 如果不支援接聽程式,請避免對接聽程式 API 執行任何呼叫。

if (ApiInformation.IsTypePresent("Windows.UI.Notifications.Management.UserNotificationListener"))
{
    // Listener supported!
}
 
else
{
    // Older version of Windows, no Listener
}

要求存取接聽程式

由於接聽程式會允許存取使用者的通知,因此使用者必須授權您的應用程式存取其通知。 在應用程式初次執行的過程中,您應該要求使用通知接聽程式的存取權。 您可以依喜好顯示一些初步 UI,說明為什麼您的應用程式需要取得使用者通知的存取權才能呼叫 RequestAccessAsync,讓使用者了解應該允許存取的原因。

// Get the listener
UserNotificationListener listener = UserNotificationListener.Current;
 
// And request access to the user's notifications (must be called from UI thread)
UserNotificationListenerAccessStatus accessStatus = await listener.RequestAccessAsync();
 
switch (accessStatus)
{
    // This means the user has granted access.
    case UserNotificationListenerAccessStatus.Allowed:
 
        // Yay! Proceed as normal
        break;
 
    // This means the user has denied access.
    // Any further calls to RequestAccessAsync will instantly
    // return Denied. The user must go to the Windows settings
    // and manually allow access.
    case UserNotificationListenerAccessStatus.Denied:
 
        // Show UI explaining that listener features will not
        // work until user allows access.
        break;
 
    // This means the user closed the prompt without
    // selecting either allow or deny. Further calls to
    // RequestAccessAsync will show the dialog again.
    case UserNotificationListenerAccessStatus.Unspecified:
 
        // Show UI that allows the user to bring up the prompt again
        break;
}

使用者隨時可透過 Windows 設定撤銷存取權。 因此,您的應用程式應該一律先透過 GetAccessStatus 方法檢查存取權狀態,再執行程式碼來使用通知接聽程式。 如果使用者撤銷存取權,API 將會失敗且不會顯示訊息,而不會擲回例外狀況 (例如,取得所有通知的 API 只會傳回空的清單)。

存取使用者的通知

您可以使用通知接聽程式取得使用者目前通知的清單。 只要呼叫 GetNotificationsAsync 方法,並指定您想要取得的通知類型即可 (目前唯一支援的通知類型是快顯通知)。

// Get the toast notifications
IReadOnlyList<UserNotification> notifs = await listener.GetNotificationsAsync(NotificationKinds.Toast);

顯示通知

每則通知都會以 UserNotification 表示,其提供有關通知的來源應用程式、建立通知的時間、通知的識別碼及通知本身的資訊。

public sealed class UserNotification
{
    public AppInfo AppInfo { get; }
    public DateTimeOffset CreationTime { get; }
    public uint Id { get; }
    public Notification Notification { get; }
}

AppInfo 屬性提供顯示通知所需的資訊。

注意

建議您將處理單一通知的所有程式碼包含在 try/catch 中,以免在您擷取單一通知時發生非預期的例外狀況。 不應該因為某一則通知發生問題,就完全無法顯示其他通知。

// Select the first notification
UserNotification notif = notifs[0];
 
// Get the app's display name
string appDisplayName = notif.AppInfo.DisplayInfo.DisplayName;
 
// Get the app's logo
BitmapImage appLogo = new BitmapImage();
RandomAccessStreamReference appLogoStream = notif.AppInfo.DisplayInfo.GetLogo(new Size(16, 16));
await appLogo.SetSourceAsync(await appLogoStream.OpenReadAsync());

通知本身的內容 (例如通知文字) 包含在通知屬性中。 此屬性包含通知的視覺效果部分。 (如果您熟悉在 Windows 上傳送通知的方式,將會注意到 Notification 物件中的 VisualVisual.Bindings 屬性對應到顯示通知時開發人員傳送的內容。)

我們想要尋找快顯通知繫結 (若是防錯誤程式碼,則應確認繫結不是 null)。 您可以從繫結中取得文字元素。 您可以選擇顯示任意數目的文字元素。 (理想情況下,您應該全部顯示。) 您可以選擇以不同方式處理文字元素;例如,將第一個視為標題文字,並將後續元素視為本文文字。

// Get the toast binding, if present
NotificationBinding toastBinding = notif.Notification.Visual.GetBinding(KnownNotificationBindings.ToastGeneric);
 
if (toastBinding != null)
{
    // And then get the text elements from the toast binding
    IReadOnlyList<AdaptiveNotificationText> textElements = toastBinding.GetTextElements();
 
    // Treat the first text element as the title text
    string titleText = textElements.FirstOrDefault()?.Text;
 
    // We'll treat all subsequent text elements as body text,
    // joining them together via newlines.
    string bodyText = string.Join("\n", textElements.Skip(1).Select(t => t.Text));
}

移除特定通知

如果您的穿戴式裝置或服務允許使用者關閉通知,您可以移除實際的通知,這樣一來,使用者之後就不會在手機或電腦上看見該通知。 只要提供您要移除之通知的通知識別碼即可 (從 UserNotification 物件取得):

// Remove the notification
listener.RemoveNotification(notifId);

清除所有通知

UserNotificationListener.ClearNotifications 方法會清除使用者的所有通知。 請慎用此方法。 只有在您的穿戴式裝置或服務顯示「所有」通知時,才清除所有通知。 如果您的穿戴式裝置或服務只顯示某些通知,當使用者按一下 [清除通知] 按鈕時,預期只會移除這些特定通知;然而,呼叫 ClearNotifications 方法會實際移除所有通知,包括您的穿戴式裝置或服務未顯示的通知。

// Clear all notifications. Use with caution.
listener.ClearNotifications();

已新增/關閉通知的背景工作

讓應用程式接聽通知的常見方式是設定背景工作,如此一來,無論您的應用程式目前是否正在執行,您都能得知何時新增或關閉通知。

現在新增背景工作相當簡單,這都要歸功於年度更新版中新增的單一處理程序模型。 在主要應用程式的程式碼中,分別呼叫 UserNotificationListener.Current.RequestAccessAsyncBackgroundExecutionManager.RequestAccessAsync 以取得使用者對通知接聽程式的存取權和執行背景工作的存取權後,只要註冊新的背景工作,並使用快顯通知類型設定 UserNotificationChangedTrigger 即可。

// TODO: Request/check Listener access via UserNotificationListener.Current.RequestAccessAsync
 
// TODO: Request/check background task access via BackgroundExecutionManager.RequestAccessAsync
 
// If background task isn't registered yet
if (!BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("UserNotificationChanged")))
{
    // Specify the background task
    var builder = new BackgroundTaskBuilder()
    {
        Name = "UserNotificationChanged"
    };
 
    // Set the trigger for Listener, listening to Toast Notifications
    builder.SetTrigger(new UserNotificationChangedTrigger(NotificationKinds.Toast));
 
    // Register the task
    builder.Register();
}

然後,在您的 App.xaml.cs 中,覆寫 OnBackgroundActivated 方法 (若尚未這樣做),並對工作名稱使用 switch 陳述式來判斷叫用了哪一個背景工作觸發程序。

protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    var deferral = args.TaskInstance.GetDeferral();
 
    switch (args.TaskInstance.Task.Name)
    {
        case "UserNotificationChanged":
            // Call your own method to process the new/removed notifications
            // The next section of documentation discusses this code
            await MyWearableHelpers.SyncNotifications();
            break;
    }
 
    deferral.Complete();
}

背景工作只是「拍肩提醒」:它不會提供新增或移除哪一則特定通知的任何資訊。 背景工作觸發時,您應該同步穿戴式裝置上的通知,使其與平台中的通知一致。 這樣可確保在背景工作失敗時,穿戴式裝置上的通知仍可在下一次背景工作執行時復原。

SyncNotifications 是您實作的方法;下一節將說明作法。

判斷新增和移除哪些通知

在您的 SyncNotifications 方法中,若要判斷新增或移除了哪些通知 (同步穿戴式裝置的通知),您必須計算目前通知集合與平台中通知之間的差異。

// Get all the current notifications from the platform
IReadOnlyList<UserNotification> userNotifications = await listener.GetNotificationsAsync(NotificationKinds.Toast);
 
// Obtain the notifications that our wearable currently has displayed
IList<uint> wearableNotificationIds = GetNotificationsOnWearable();
 
// Copy the currently displayed into a list of notification ID's to be removed
var toBeRemoved = new List<uint>(wearableNotificationIds);
 
// For each notification in the platform
foreach (UserNotification userNotification in userNotifications)
{
    // If we've already displayed this notification
    if (wearableNotificationIds.Contains(userNotification.Id))
    {
        // We want to KEEP it displayed, so take it out of the list
        // of notifications to remove.
        toBeRemoved.Remove(userNotification.Id);
    }
 
    // Otherwise it's a new notification
    else
    {
        // Display it on the Wearable
        SendNotificationToWearable(userNotification);
    }
}
 
// Now our toBeRemoved list only contains notification ID's that no longer exist in the platform.
// So we will remove all those notifications from the wearable.
foreach (uint id in toBeRemoved)
{
    RemoveNotificationFromWearable(id);
}

新增/關閉通知的前景事件

重要

已知問題:在組建 17763/2018 年 10 月更新/版本 1809 之前的組建中,前景事件會導致 CPU 迴圈和/或無法運作。 如果您需要這些舊版組建的支援,請改用背景工作。

您也可以接聽來自記憶體內事件處理常式的通知...

// Subscribe to foreground event
listener.NotificationChanged += Listener_NotificationChanged;
 
private void Listener_NotificationChanged(UserNotificationListener sender, UserNotificationChangedEventArgs args)
{
    // Your code for handling the notification
}

如何修正背景工作的延遲

測試應用程式時,您可能會注意到背景工作有時會延遲,而且有數分鐘的時間未觸發。 若要修正延遲,請提示使用者前往系統設定 -> [系統] -> [電池] -> [應用程式的電池使用情況],在清單中尋找您的應用程式,並將它設定為 [一律允許在背景中執行]。設定完成後,背景工作應該一律會在收到通知後的一秒內觸發。