c# - 应用程序在后台时如何正确通知当前视图模型有关推送通知
问题描述
我正在使用 Xamarin 和 MvvmCross 为 iOS 和 Android 平台开发手机应用程序。在 Android 版本中,我可以在应用程序处于前台时和应用程序关闭时接收推送通知,并在这两种情况下导航到所需的视图模型。
当应用程序处于后台并由于用户点击推送通知而恢复时,我无法从初始屏幕导航到特定视图模型。
如果设置了该标志并执行导航,我可以保留一个标志,然后检查恢复的每个视图模型,但我不太喜欢该解决方案,并且希望像应用程序处于前台时那样使用事件。问题是当应用程序处于后台并从推送通知恢复时,我的事件仍未分配给它的处理程序。
这是我的代码。闪屏:
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);
}
这是我获取推送通知信息并触发我的 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);
}
但是当应用程序来自后台时,这些事件处理程序为空,因为视图尚未出现。我无法在构造函数中附加事件的处理程序,因为当视图消失时我无法删除它。只有当前的视图模型应该处理事件并导航到我想要的视图模型。
我也尝试过 MvxMessenger 插件但没有成功。
所以我的问题是,当应用程序在后台时,如何正确通知我的视图模型推送通知?