I'm developing a cellphone app for iOS and Android platforms using Xamarin and MvvmCross. I can receive push notifications while the app is in foreground and in background.
When the app is closed, I also receive the push notifications and when I click on them, the app starts but I know no way to distinguish if the app started because of user clicked on the app icon or because the push notification was clicked. I want to navigate to a concrete view model when the app was closed and is started by a push notification.
I've found this article, which proposes a solution I didn't implement yet, that could solve the problem in platform dependant code (iOS):
Also pointing this direction there's this answer in the xamarin forums:
https://forums.xamarin.com/discussion/67698/ios-notifications-while-app-is-closed
If the user taps on the banner displayed, the >AppDelegate.FinishedLaunching method is called. The NSDictionary of >options passed in will contain >UIApplication.LaunchOptionsRemoteNotificationKey to let you know the >app was launched because of a push notification. You can check for this >and handle it accordingly for your app. i.e. Display an alert, navigate >to a page, etc.
My question though is, how can I do that in the Core project shared by the different platforms? I've followed the steps shown at the end of this article in he MvvmCross documentation:
https://www.mvvmcross.com/documentation/advanced/customizing-appstart
So my code looks as follows:
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);
}
}
Custom 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://stackguides.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);
}
}
Extract of first view model
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}");
}
I expected this implementation to receive some parameter in the hint parameter of the custom app start class in the NavigateToFirstViewModel method and then in the prepare method of the first view model (AppSyncViewModel) set a flag to know if we opened the app from a push notification, depending on this parameter.
The result, though, is that the parameter is always null, even when the app is closed and it starts from a push notification.
So, to summarise my question, how can I detect, in Core project using MvvmCross that the app started from a push notification?