Проблема: разное поведение в 3 разных контекстах
Хорошо, так хорошо, в iOS кажется, что с Push-уведомлениями могут происходить три вещи:
- При получении Push-уведомления, когда приложение не на переднем плане
- что-то появляется в Центре уведомлений
- если приложение открывается нажатием на уведомление, вызывается или
AppDelegate.DidReceiveRemoteNotification(...)
или AppDelegate.ReceivedRemoteNotification(...)
, очевидно, в зависимости от того, какое из них реализовано (??).
- если приложение открыто без нажатия на уведомление, вызывается only
AppDelegate.WillEnterForeground(...)
, без какого-либо явного упоминания об уведомлении, и ничего больше не подтверждает, что уведомление был получен.
- При получении Push-уведомления, когда приложение находится на на переднем плане, оно вызывает
UNUserNotificationCenterDelegate
, если оно есть, для выполнения UNUserNotificationCenterDelegate.WillPresentNotification(...)
.
Подход: маршрутизация к одному методу из всех контекстов
Итак, чтобы покрыть все базы с помощью Push, мне нужно реализовать что-то во всех трех методах: AppDelegate.DidReceiveRemoteNotification(...) / AppDelegate.ReceivedRemoteNotification(...)
, AppDelegate.WillEnterForeground(...)
и UNUserNotificationCenterDelegate .WillPresentNotification(...)
.
Вот несколько заглушек, чтобы показать мой подход ко всему этому.
Сначала я создал пользовательский UNUserNotificationCenterDelegate
со статическим членом Shared
:
public class IncomingNotificationHandler : UNUserNotificationCenterDelegate
{
public static IncomingNotificationHandler Shared = new IncomingNotificationHandler();
...
}
Во-вторых, внутри этого класса я создал обработчик, к которому я могу направлять в каждом случае (опять же, это просто заглушка для целей отладки):
//sets all parameters to null by default, so it can be called from methods
//that don't know anything about notifications:
public void HandleNotificationsIfAny(UIApplication application = null,
NSDictionary userInfo = null,
Action<UIBackgroundFetchResult> completionHandler = null)
{
//checks if userInfo is null, and logs its conclusions about that:
if (userInfo == null)
{
//In the null case, we can get pending notifications from
//UNUserNotificationCenter:
UNNotification[] pendingNotifications = new UNNotification[] { };
UNUserNotificationCenter.Current.GetDeliveredNotifications(returnedValue => pendingNotifications = returnedValue);
//Then we log the number of pending notifications:
Debug.WriteLine("IncomingNotificationHandler: HandleNotificationsIfAny(...): delivered notification count: " + pendingNotifications.Length);
//And make note of where this was probably called from:
Debug.WriteLine("IncomingNotificationHandler: HandleNotificationsIfAny(...): may have been called from this.WillPresentNotification(...) OR AppDelegate.WillEnterForeground(...)");
return;
});
}
else
{
//In the non-null case, we log the userInfo
Debug.WriteLine("IncomingNotificationHandler: HandleNotificationsIfAny(...): just got info: " + userInfo);
//And make note of where this was probably called from:
Debug.WriteLine("IncomingNotificationHandler: HandleNotificationsIfAny(...): may have been called from AppDelegate.DidReceiveRemoteNotification(...)");
}
}
В-третьих, внутри того же класса я реализовал единственный метод, необходимый для UNUserNotificationCenterDelegate
, и перенаправил его на обработчик:
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
HandleNotificationsIfAny();
}
Четвертый и последний, внутри AppDelegate
, я перенаправил на один и тот же обработчик обоими соответствующими методами:
//I prefer using DidReceiveRemoteNotification because in my experience
//the other one is sometimes not reliable:
public override void DidReceiveRemoteNotification(UIApplication application,
NSDictionary userInfo,
Action<UIBackgroundFetchResult> completionHandler)
{
//Simply passing on all the parameters called in this method:
IncomingNotificationHandler.Shared.HandleNotificationsIfAny(application, userInfo, completionHandler);
}
//WillEnterForeground also calls the handler without any parameters
//because it doesn't automatically know anything about notifications:
public override void WillEnterForeground(UIApplication application)
{
IncomingNotificationHandler.Shared.HandleNotificationsIfAny();
}
С учетом этого, я думаю, что я обрабатываю событие уведомления одинаково, независимо от того, как мое приложение уведомлено об этом, и даже когда оно вообще не предупреждено.
Кто-нибудь знает, покрыл ли я это сейчас, или есть ли другие случаи, которые мне нужно обработать?