如何在Xamarin.forms中使用推送通知恢复应用程序并打开特定页面

3
我目前正在开发一个适用于iOS和Android的Xamarin应用程序,但我将要解释的问题仅涉及Android应用程序(这在iOS应用程序中尚未实现)。
实际上,当我接收到给定的推送通知时,需要打开应用程序中的特定页面。如果应用程序在接收到推送通知时处于打开状态,则非常有效,但是如果我的应用程序关闭或在后台运行,则应用程序会崩溃。
如此,当我接收到通知时,我最终进入了名为"OnShouldOpenCommand"的方法:
  private void OnShouldOpenCommand(string commandId)
        {
            NotifyNewCommand(AppResources.AppName, AppResources.CommandNotificationText, commandId);

            Device.BeginInvokeOnMainThread(() =>
            {
                try
                {

                    App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(commandId))
                    {
                        BarBackgroundColor = Color.FromHex("1e1d1d")
                    };

                    App.MasterDetailPage.NavigationStack.Push(((NavigationPage)(App.MasterDetailPage.Detail)).CurrentPage);
                }
                catch(Exception e)
                {                   
                        Log.Debug("PushAsync", "Unable to push CommandAcceptancePage : "+ex.Message);
                }

            });
        }

    private void NotifyNewCommand(string Title,string Description, string commandId)
    {
        var intent = new Intent(this, typeof(MainActivity));
        if (!String.IsNullOrEmpty(commandId))
        {
            intent.PutExtra("CommandId", commandId);
        }
        intent.AddFlags(ActivityFlags.ClearTop);
        var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);

        var notificationBuilder = new Notification.Builder(this)
            .SetSmallIcon(Resource.Drawable.icon)
            .SetContentTitle("Kluox")
            .SetContentText(Description)
            .SetAutoCancel(true)
            .SetContentIntent(pendingIntent);

        Notification notification = notificationBuilder.Build();

        var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
        notificationManager.Notify(0, notification);
    }

并且这段代码

App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(commandId))
                    {
                        BarBackgroundColor = Color.FromHex("1e1d1d")
                    };

出现了以下类型的异常:

Java.Lang.IllegalStateException:在保存实例状态之后无法执行此操作

所以我想,如果我的应用程序没有运行在前台,我就不能访问“App”并重定向到另一个页面。好吧,这就是当我收到推送通知而不是点击它时发生的情况。但是,我不打算通过这种方式重新打开我的应用程序。

因为在那之后,当我点击名为Kluox的推送通知时(这应该重新打开我的应用程序),应用程序会崩溃,我真的不知道为什么,我不知道在哪里设置断点以便进行调试,因为 Visual Studio 只告诉我“发生了未处理的异常”。

enter image description here

有人可以帮我吗?如果您需要任何代码片段,您只需问我,我将编辑我的消息并提供您所需的任何信息!

编辑 1: 这是我的OnCreate方法的代码:

protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);
            var info = Intent.Extras?.GetString("CommandId", "");
            global::Xamarin.Forms.Forms.Init(this, bundle);
            if (String.IsNullOrEmpty(info))
            {
                LoadApplication(new App());
            }
            else
            {
                LoadApplication(new App(info));
            }
            if (instance == null)
            {
                instance = this;
                RegisterWithGCM();
            }
            else
            {
                instance = this;
            }
        }

我也想知道答案!请有人帮忙! - Augustin Bocken
以防万一,我发现有人遇到相同的问题,但还没有回复:https://forums.xamarin.com/discussion/comment/261562#Comment_261562 - Augustin Bocken
2个回答

2

幸运的是,我几天前就在那里,并花了很多时间在Android上使其工作(iOS仍在努力中)。

当你杀死你的应用程序并再次从图标或通知实例化它时,在这两种情况下,你将进入主活动。

如果我们想要从实例化它的通知中在主活动中获取一些信息,我们可以在 OnCreate() 中这样做:

var info = Intent.Extras?.GetString("info", "");

现在针对您的情况,我会在通知中添加额外的信息,显示该通知所涉及的视图/页面,例如名称等。
这个额外的信息可以在加载应用程序之前传递给应用程序的构造函数。
在应用程序的构造函数中,您可以检查是否有额外的信息,如果没有,则表示启动应用程序的主页是默认的MainPage,否则它是某个页面。

我现在试一下,之后会给你反馈,无论如何感谢你的帮助! - Antoni Maniscalco
嘿,我正在与Anto Maniscalco合作,我们尝试了你的解决方案,但是我们仍然遇到同样的问题。 当我们创建通知时,我们添加了intent.PutExtra("CommandId", commandId); 在OnCreate中,我们有 var info = Intent.Extras?.GetString("CommandId", ""); global::Xamarin.Forms.Forms.Init(this, bundle); if (String.IsNullOrEmpty(info)) { LoadApplication(new App()); } else { LoadApplication(new App(info)); } - Augustin Bocken
你确定你获取的信息是正确的吗?也许你可以在这里添加一个提示框,显示你获取的信息。 - Ahmad ElMadi
为了能够继续调试,我没有杀死应用程序,而是将其放在后台(这也更符合将要对应用程序进行的使用),代码正在添加到问题中。 - Augustin Bocken
1
很好,如果应用程序正在运行,那么它肯定不会进入OnCreate(),但它会进入"OnResume" 我首先想到的是使用MessagingCenter并将PageName发送到那里。 然后你可以从任何地方订阅它,一旦消息被触发,它将在共享项目内处理。这样你就可以做任何你想做的事情 :) - Ahmad ElMadi
显示剩余3条评论

2

在覆盖了MainActivity的所有方法之后,我终于找到了崩溃的原因:方法OnDestroy被调用了两次,并抛出了IllegalStateException异常,因为该活动已经被销毁。我找到了这个解决方法:

 protected override void OnDestroy()
        {
            try
            {
                base.OnDestroy();
            }
            catch (Java.Lang.IllegalStateException ex)
            {
                Log.Debug("MainActivity.OnDestroy", ex, "The activity was destroyed twice");
            }

        }

当异常被记录时,应用程序可以正常打开并使用。

当重定向也起作用时,我会编辑这个答案。

编辑:如何重定向到一个页面

首先,在构造函数中我们需要注册 MessagingCenter。

public static MyPackage.Model.Command CurrentCommand { get; set; }
public App()
{
    InitializeComponent();
    MainPage = new ContentPage();
    MessagingCenter.Subscribe<object, DataLib.Model.Command>(this, "Command", (sender, arg) => {
      try
      {
         CurrentCommand = arg;
      }
      catch(Exception ex)
      {
         CurrentCommand = null;
      }
    });
  }

当我们收到推送通知时,发送消息:
private void OnMessage(string serializedCommand)
{
  //stuff happens
  MessagingCenter.Send<object, MyPackage.Model.Command>(this, "Command", command);
}

最后,当我们获取App.Xaml.cs的OnStart()时。
                if (CurrentCommand != null)
                {
                    App.MasterDetailPage.Detail = new NavigationPage(new CommandAcceptancePage(CurrentCommand, service))
                    {
                        BarBackgroundColor = Color.FromHex("1e1d1d")
                    };
                }

目前看来,它好像起到了作用!还需要更多的调试,但代码似乎能够工作。非常感谢 @BraveHeart 的帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接