Как пометить закрытое приложение, запущенное из push-уведомлений, используя MvvmCross с запуском собственного приложения - PullRequest
0 голосов
/ 08 февраля 2019

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

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

Я нашел эту статью, в которой предлагается решение, которое я еще не реализовал, которое могло бы решитьпроблема в платформо-зависимом коде (iOS):

https://theconfuzedsourcecode.wordpress.com/2015/09/22/handling-push-notifications-in-xamarin-ios-when-app-is-closed/

Также в этом направлении есть ответ на форумах xamarin:

https://forums.xamarin.com/discussion/67698/ios-notifications-while-app-is-closed

Если пользователь нажимает на отображаемый баннер, вызывается метод> AppDelegate.FinishedLaunching.Переданные параметры NSDictionary of> будут содержать> UIApplication.LaunchOptionsRemoteNotificationKey, чтобы сообщить, что приложение> было запущено из-за push-уведомления.Вы можете проверить это> и обработать его соответствующим образом для своего приложения.т.е. отображать предупреждение, переходить> на страницу и т. д.

Однако у меня вопрос: как я могу это сделать в проекте Core, совместно используемом различными платформами?Я выполнил шаги, показанные в конце этой статьи в документации MvvmCross:

https://www.mvvmcross.com/documentation/advanced/customizing-appstart

Итак, мой код выглядит следующим образом:

App.cs

public class App : MvxApplication<object>
{
    public override void Initialize()
    {
        CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IAppStartSynchronizer, AppStartSynchronizer>();
        Mvx.IoCProvider.RegisterSingleton(() => UserDialogs.Instance);

        RegisterCustomAppStart<HaasSohnAppStart<AppSyncViewModel>>();
    }

    public override object Startup(object parameter)
    {
        //never reached
        Console.WriteLine("APP.CS STARTUP");
        return base.Startup(parameter);          
    }
}

Пользовательский AppStart

public class HaasSohnAppStart<AppSyncViewModel> : MvxAppStart<AppSyncViewModel, object> where AppSyncViewModel : IMvxViewModel<object>
{
    public HaasSohnAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService){}

    /// <summary>
    /// Don't await the navigation to the first view model to be able to do async operations in the first <typeparamref name="AppSyncViewModel"/>
    /// see: https://nicksnettravels.builttoroam.com/post/2018/04/19/MvvmCross-Initialize-method-on-the-first-view-model.aspx
    /// see: https://stackoverflow.com/questions/49865041/mvvmcross-app-wont-start-after-upgrading-to-version-6-0 
    /// see: https://github.com/MvvmCross/MvvmCross/issues/2829
    /// </summary>
    /// <param name="hint">Hint.</param>
    protected override Task NavigateToFirstViewModel(object hint)
    {
            //First of all configure app synchronously to have db connection, api urls, translations, etc configured
        AppConfig.Initialize().GetAwaiter().GetResult();
        NavigationService.Navigate<AppSyncViewModel, object>(hint);
        return Task.CompletedTask;
    }

    protected override Task<object> ApplicationStartup(object hint = null)
    {
        //hint always null
        Console.WriteLine($"APPSTART APPLICATION STARTUP HINT = {hint}");
        return base.ApplicationStartup(hint);
    }
}

Извлечение модели первого вида

public class AppSyncViewModel : BaseViewModel, IMvxViewModel<object>
{
    private IAppStartSynchronizer _appSyncrhronizer;
    private INetworkAvailable _networkAvailable;
    private MainController _mainController = MainController.Instance;
    override public string Title => Strings["AppSyncViewModel_Label_Title"];

    public string SyncInfo { get; set; } = "AppSyncViewModel_Label_SyncInProgress".Translate();

    private bool _comeFromPushNotification;
    public AppSyncViewModel(IMvxNavigationService navigationService, IAppStartSynchronizer appSynchronizer, INetworkAvailable networkAvailable, IUserDialogs userDialogs) : base(navigationService, userDialogs)
    {
        _appSyncrhronizer = appSynchronizer;
        _networkAvailable = networkAvailable;
    }

    public override async Task Initialize()
    {
        if (_appSyncrhronizer != null)
        {
            IsBusy = true;
            _appSyncrhronizer.SyncFinish += Syncnronizer_SyncFinish;
            await _appSyncrhronizer.StartupSync(_networkAvailable);
        }

        await base.Initialize();
    }

    public async void Syncnronizer_SyncFinish(object sender, System.EventArgs e)
    {
        if (_comeFromPushNotification)
        {
            await _userDialogs.AlertAsync("we come from push notification", "parameter");
        }            
    }        

    public void Prepare(object parameter)
    {
        //parameter always null
        _comeFromPushNotification = parameter != null ? true : false;
        Console.WriteLine($"APPSYNCVIEWMODEL: parameter = {parameter}");
    }

Я ожидал, что эта реализация получит некоторый параметр в параметре подсказки при запуске пользовательского приложениякласс в методе NavigateToFirstViewModel, а затем в методе prepare первой модели представления (AppSyncViewModel) установите флаг, чтобы узнать, открывали ли мы приложение из push-уведомления, в зависимости от этого параметра.

В результате получается, что параметр всегда равен нулю, даже если приложение закрыто и запускается из push-уведомления.

Итак, чтобы подвести итог моего вопроса, как я могу обнаружить, в проекте Core, использующем MvvmCross, чтобы приложение запускалось из push-уведомления?

1 Ответ

0 голосов
/ 08 февраля 2019

Таким образом, причина, по которой вы возвращаете значение null для подсказки, заключается в том, что MvvmCross переопределяет переданный объект в null в MvxApplicationDelegate.

Так, когда вы нажимаете push-уведомление на iOS, вызывается метод FinishedLaunching с параметром NSDictionary, заполненным LaunchOptionsRemoteNotificationKey.Что происходит, так это то, что этот ключ переопределяется на нуль, а не передается.

Вы можете видеть, что это происходит в исходном коде MvvmCross здесь

Таким образом, вы можете исправить эту проблему в своем классе ApplicationDelegate, переопределить GetAppStartHint и реализовать его следующим образом:

protected override object GetAppStartHint(object hint = null)
{
    return hint;
}

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

...