Поделиться через


Прослушиватель уведомлений: доступ ко всем уведомлениям

Прослушиватель уведомлений предоставляет доступ к уведомлениям пользователя. Смарт-часы и другие носимые устройства могут использовать прослушиватель уведомлений для отправки уведомлений телефона на носимое устройство. Приложения домашней автоматизации могут использовать прослушиватель уведомлений для выполнения определенных действий при получении уведомлений, таких как создание мигания света при получении звонка.

Внимание

Требуется юбилейное обновление: необходимо установить целевой пакет SDK 14393 и запустить сборку 14393 или более поздней версии для использования прослушивателя уведомлений.

Важные API: класс UserNotificationListener, класс 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
}

Запрос доступа к прослушивателю

Так как прослушиватель разрешает доступ к уведомлениям пользователя, пользователи должны предоставить приложению разрешение на доступ к их уведомлениям. Во время первого запуска приложения необходимо запросить доступ к прослушивателю уведомлений. Если вы хотите, вы можете отобразить некоторый предварительный пользовательский интерфейс, который объясняет, почему ваше приложение должно получить доступ к уведомлениям пользователя перед вызовом 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());

Содержимое самого уведомления, например текста уведомления, содержится в свойстве Notification . Это свойство содержит визуальную часть уведомления. (Если вы знакомы с отправкой уведомлений в Windows, вы заметите, что Свойства Visual и Visual.Bindings в объекте Notification соответствуют тому, что разработчики отправляют при появлении уведомления.)

Мы хотим искать всплывающую привязку (для кода проверки ошибок следует проверить, что привязка не имеет значения 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.RequestAccessAsync и BackgroundExecutionManager.RequestAccessAsync соответственно, просто зарегистрируйте новую фоновую задачу и задайте UserNotificationChangedTrigger с помощью типа уведомления Toast.

// 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 г. Обновление / версия 1809, событие переднего плана приведет к циклу ЦП и /или не работало. Если вам нужна поддержка в предыдущих сборках, используйте фоновую задачу.

Вы также можете прослушивать уведомления из обработчика событий в памяти...

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

Устранение задержек в фоновой задаче

При тестировании приложения можно заметить, что фоновая задача иногда задерживается и не запускается в течение нескольких минут. Чтобы устранить задержку, предложите пользователю перейти к параметрам системы - Система ->> Батареи -> Использование батареи по приложению, найти приложение в списке, выбрать его и задать для него значение "Всегда разрешено в фоновом режиме". После этого фоновая задача всегда должна запускаться в пределах секунды полученного уведомления.