Как правильно уведомить текущую модель представления о push-уведомлении, когда приложение находится в фоновом режиме - PullRequest
0 голосов
/ 14 февраля 2019

Я разрабатываю мобильное приложение для платформ iOS и Android, используя Xamarin и MvvmCross.В версии для Android я могу получать push-уведомления, когда приложение находится на переднем плане и когда приложение закрыто, и перейти к нужной модели представления в этих двух случаях.

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

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

Это мой код.SplashScreen:

public class SplashScreen : MvxSplashScreenAppCompatActivity
{
    private bool _setPushNotificationHint;
    private Dictionary<string, string> _pushNotificationData;

    public SplashScreen() : base(Resource.Layout.SplashScreenLayout)
    {
    }
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        if (Intent.Extras != null)
        {
            _pushNotificationData = new Dictionary<string, string>();
            foreach (var key in Intent.Extras.KeySet())
            {
                var value = Intent.Extras.Get(key);
                if(value != null)
                {
                    _pushNotificationData.Add(key, value.ToString());
                }                   
            }
            _setPushNotificationHint = true;
        }

        //avoid showing splash screen when resuming app pressing app icon or when tapping on push notification
        if (!IsTaskRoot)
        {
            //deliver notification only when app is started and is in background. When it's closed we'll use GetAppStartHint
            if (_setPushNotificationHint)
            {
                PushNotificationManager.OnMessageReceivedAppInBackground(this, _pushNotificationData);
            }
            Finish();
            return;
        }
        //just initialize essentials when first start of the app, not when splash screen is shown
        Xamarin.Essentials.Platform.Init(this, bundle);
    }

Здесь я получаю информацию о push-уведомлениях и запускаю свой PushNotificationManager, который должен вызвать событие.Вот выдержка из этого:

public class PushNotificationManager : IPushNotification
{
    public const string controlIdKey = "controlId";

    private static PushNotificationDataEventHandler _onNotificationReceived;
    public event PushNotificationDataEventHandler OnNotificationReceived
    {
        add
        {
            _onNotificationReceived += value;
        }
        remove
        {
            _onNotificationReceived -= value;
        }
    }

    private static PushNotificationDataEventHandler _onNotificationReceivedWhileForeground;
    public event PushNotificationDataEventHandler OnNotificonReceivedWhileForegroundationReceived
    {
        add
        {
            _onNotificationReceivedWhileForeground += value;
        }
        remove
        {
            _onNotificationReceivedWhileForeground -= value;
        }
    }

    /// <summary>
    /// Handles an incoming push notification in Android when app is in Foreground.
    /// </summary>
    /// <param name="remoteMessage">User info.</param>
    public static void OnMessageReceived(RemoteMessage remoteMessage)
    {
        var notification = CreateNotificationFromRemoteMessage(remoteMessage);
        _onNotificationReceivedWhileForeground?.Invoke(CrossPushNotification.Instance, new PushNotificationDataEventArgs(notification));
    }

    /// <summary>
    /// When app is in background in Android, we get to the splashscreen, who will call this method to publish a NotificationMessage to the interested ViewModels
    /// </summary>
    /// <param name="sender">Sender.</param>
    /// <param name="parameters">Parameters.</param>
    public static void OnMessageReceivedAppInBackground(object sender, Dictionary<string, string> parameters)
    {
        var notification = CreateNotificationFromIntentExtras(parameters);
        //we need to publish a message instead of rising an event because this is triggered from the splash screen and the view model 
        //Mvx.IoCProvider.Resolve<IMvxMessenger>().Publish(notificationMessage);
        //_onNotificationReceived?.Invoke(CrossPushNotification.Instance, new PushNotificationDataEventArgs(notification));
        //todo find a way to properly notify the current view to navigate to the device details view model
    }

    /// <summary>
    /// In Android plataform, we create the notification from the parameters received in the splashscreen as intent extras
    /// </summary>
    /// <returns>The notification from intent extras.</returns>
    /// <param name="parameters">Parameters.</param>
    private static Notification CreateNotificationFromIntentExtras(Dictionary<string, string> parameters)
    {
        parameters.TryGetValue(controlIdKey, out var controlId);

        return new Notification
        {
            ControlId = controlId
        };
    }

Затем в BaseViewModel.cs я присоединяю обработчик событий, которые должны быть запущены из PushNotificationManager:

public override void ViewAppeared()
    {
        base.ViewAppeared();
        //_token = Mvx.IoCProvider.Resolve<IMvxMessenger>().Subscribe<NotificationMessage>(OnNotificaitonMessage);
        CrossPushNotification.Instance.OnNotificationReceived += NotificationReceived;
        CrossPushNotification.Instance.OnNotificonReceivedWhileForegroundationReceived += NotificationInForegroundReceived;
    }

    public override void ViewDisappeared()
    {
        base.ViewDisappeared();
        //Mvx.IoCProvider.Resolve<IMvxMessenger>().Unsubscribe<NotificationMessage>(_token);
        CrossPushNotification.Instance.OnNotificationReceived -= NotificationReceived;
        CrossPushNotification.Instance.OnNotificonReceivedWhileForegroundationReceived -= NotificationInForegroundReceived;
    }

    public override void ViewDestroy(bool viewFinishing = true)
    {
        //Mvx.IoCProvider.Resolve<IMvxMessenger>().Unsubscribe<NotificationMessage>(_token);
        CrossPushNotification.Instance.OnNotificationReceived -= NotificationReceived;
        CrossPushNotification.Instance.OnNotificonReceivedWhileForegroundationReceived -= NotificationInForegroundReceived;
        base.ViewDestroy(viewFinishing);
    }

Но эти обработчики событийnull, когда приложение приходит из фона, потому что представление еще не появилось.Я не могу прикрепить обработчик событий в конструкторе, потому что тогда я не могу удалить его, когда представление исчезает.Только текущая модель представления должна обработать событие и перейти к моей желаемой модели представления.

Я также безуспешно пытался подключить плагин MvxMessenger.

Поэтому мой вопрос заключается в том, как правильно уведомить моюпросмотреть модели, когда push-уведомление пришло, когда приложение было в фоновом режиме?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...