xamarin - 在 Xamarin Forms Android 中处理通知

标签 xamarin xamarin.android xamarin.forms android-notifications

我正在使用库 https://github.com/aritchie/notifications我可以正确地创建和安排通知。

我希望在 Android 中处理它们,以便根据通知 - 当用户点击它时它将导航到特定页面。

我发现当我点击通知(在我的 Android 项目中)时会触发以下事件

 protected override void OnNewIntent(Intent intent)
    {

    }

但是,我在通知中找不到意图中的任何信息,以便建立到特定页面的导航。

如有任何建议,我们将不胜感激。

干杯!

编辑 #1(为相关问题添加其他代码):

如果我发出通知,并在收到通知之前关闭应用程序 - 我会收到一条错误消息,指出应用程序已崩溃。如果我收到通知并关闭应用程序 - 我可以从通知加载应用程序。

我有一个依赖服务,它使用以下方法。

public void Remind(DateTime dateTime, string msgtype, string usermedid)
    {
        DateTime now = DateTime.Now;
        var diffinseconds = (dateTime - now).TotalSeconds;
        Intent alarmIntent = new Intent(Forms.Context, typeof(AlarmBroadcastReceiver));
        alarmIntent.PutExtra("notificationtype", msgtype);
        alarmIntent.PutExtra("id", id);


        PendingIntent pendingIntent = PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        AlarmManager alarmManager = (AlarmManager)Forms.Context.GetSystemService(Context.AlarmService);

        //TODO: For demo set after 5 seconds.
        alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);

    }

    [BroadcastReceiver(Enabled = true)]
    [IntentFilter(new string[]{"android.intent.action.BOOT_COMPLETED"}, Priority = (int) IntentFilterPriority.LowPriority)]
    public class AlarmBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            string notificationtype = intent.GetStringExtra("notificationtype");

            PowerManager.WakeLock sWakeLock;
            var pm = PowerManager.FromContext(context);
            sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Reciever Tag");
            sWakeLock.Acquire();

            intent = new Intent(Forms.Context, typeof(MainActivity));
            intent.PutExtra("notificationtype", notificationtype);
            intent.AddFlags(ActivityFlags.IncludeStoppedPackages);



            // Instantiate the builder and set notification elements, including pending intent:
            NotificationCompat.Builder builder = new NotificationCompat.Builder(Forms.Context)
                .SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
                .SetAutoCancel(true)
                .SetContentIntent(PendingIntent.GetActivity(Forms.Context, 0, intent, 0)).SetContentTitle("Sample Notification")
                .SetContentText("Hello World! This is my first action notification!")
                .SetTicker("New Notification")

                .SetSmallIcon(Resource.Drawable.icon);


            // Build the notification:
            Android.App.Notification notification = builder.Build();

            notification.Flags = NotificationFlags.AutoCancel;

            // Get the notification manager:
            //NotificationManager notificationManager = Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;
            var manager = NotificationManagerCompat.From(context);

            // Publish the notification:
            const int notificationId = 0;
            manager.Notify(notificationId, notification);

            sWakeLock.Release();



        }
    }

当应用程序关闭时,如何使广播接收器保持事件状态?

最佳答案

好吧,我花了一些时间才弄清楚这个问题。当应用程序位于后台并且单击通知时,将调用 OnNewIntent。每次应用程序最小化和恢复时也会调用它...因此为了区分这两个事件之间的区别,您需要检查传入的 Intent 以了解其中包含哪些额外数据。额外的数据将来自您首次启动通知时所做的Intent

另外,请确保将 MainActivityLaunchMode 设置为 LaunchMode.SingleTop,这样您的应用就不会在每次收到通知时重新启动被点击。

[Activity(LaunchMode = LaunchMode.SingleTop, ....)]
public class MainActivity : FormsApplicationActivity {

    ....

    /// <summary>
    /// Called when the app is in the background and a notification is clicked on (also called each time the app is minimized and the brought back up), a new <c>Intent</c> is created
    ///     and sent out, since we use <c>LaunchMode</c> set to <c>SingleTop</c> this method is called instead of the app being restarted.
    /// </summary>
    /// <param name="intent">The <c>Intent</c> that was set when the call was made. If started from a notification click, extra <c>string</c> values can be extracted.</param>
    protected override void OnNewIntent(Intent intent) {

        if(intent.HasExtra("Some special key you made up")) { //Here is where you check for special notification intent extras
            //Do something brilliant now that you know a notification was clicked on
        }
        base.OnNewIntent(intent);
    }

要了解如何将数据添加到 Intent,您可以查看 the Xamarin Sport App ,但不要像我总是倾向于做的那样,过多地陷入他们正在做的所有其他事情中。只需关注 PutExtra 部分即可。

编辑#1:

如果您的应用完全关闭,您需要从传递到 OnCreateIntent 中提取数据,并将其传递到您的 App 类中或者用它做其他事情:

protected override async void OnCreate(Android.OS.Bundle bundle) {

    base.OnCreate(bundle);

    Forms.Init(this, bundle);

    string parameterValue = Intent.GetStringExtra("Some special key you made up"); //This would come in from the Push Notification being clicked on

    Console.WriteLine("\nIn MainActivity.OnCreate() - Param Intent Extras: {0}\n", parameterValue);

    //MessagingCenter.Send("nothing", ConstantKeys.NewNotification); //Do something special with the notification data

    LoadApplication(parameterValue != null ? new App(parameterValue) : new App()); //Do something special with the notification data
}

编辑#2:

我会根据我当前的代码建议您对 OnReceive 方法进行一些更改(有些可能不是必需的,但这正是我正在做的事情):

  • Label your Broadcast Receiver
  • Add stupid Xamarin constructors
  • Used constant property instead of string for IntentFilter
  • Remove IntentFilter Priority
  • Check for null Intent (might not be necessary)
  • Use Application.Context instead of Forms.Context (I use Forms.Context in other parts of my app so not sure about this one, but can't hurt)
  • Do not overwrite the passed in Intent
  • Create startup intent instead of regular
  • Add IncludeStoppedPackages flag before pulling out extras
  • Check for boot completed event
  • Use Notification.Builder instead of NotificationCompat.Builder (though you might need to change this back)
  • Add following flags to pendingintent: PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot -- Use NotificationManager (unless you have a specific reason you commented it out)
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]  
[assembly: UsesPermission(Android.Manifest.Permission.WakeLock)]                //Optional, keeps the processor from sleeping when a message is received
[assembly: UsesPermission(Android.Manifest.Permission.ReceiveBootCompleted)]                        //Allows our app to be opened and to process notifications even when the app is closed

namespace Your.App.Namespace {

[BroadcastReceiver(Enabled = true, Label = "GCM Alarm Notifications Broadcast Receiver")]
[IntentFilter(new []{ Intent.ActionBootCompleted })]
public class AlarmBroadcastReceiver : BroadcastReceiver {
    #region Constructors

    // ReSharper disable UnusedMember.Global
    public AlarmBroadcastReceiver() { }

    public AlarmBroadcastReceiver(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { }
    // ReSharper restore UnusedMember.Global

    #endregion

    public void Remind(DateTime dateTime, string msgtype, string usermedid) {
        DateTime now = DateTime.Now;
        var diffinseconds = (dateTime - now).TotalSeconds;

        Intent alarmIntent = new Intent(Application.Context, typeof(AlarmBroadcastReceiver));
        alarmIntent.PutExtra("notificationtype", msgtype);
        alarmIntent.PutExtra("id", id);

        PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        AlarmManager alarmManager = (AlarmManager)Application.Context.GetSystemService(Context.AlarmService);

        //TODO: For demo set after 5 seconds.
        alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);
    }

    public override void OnReceive(Context context, Intent intent) {
        #region Null Check

        if(intent == null) {
            Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Intent is null\n");
            return;
        }

        #endregion

        intent.AddFlags(ActivityFlags.IncludeStoppedPackages);

        string action = intent.Action;
        Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Action: {0}\n", action);

        #region Boot Completed Check

        if(action.Equals("android.intent.action.BOOT_COMPLETED")) {

            PowerManager pm = PowerManager.FromContext(context);
            PowerManager.WakeLock sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Receiver Tag");
            sWakeLock.Acquire();

            Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Process Shared Preferences Notifications\n");

            #region Process Saved Scheduled Notifications

            //Get list of saved scheduled notifications that did not fire off before the device was turned off (I store them in SharedPreferences and delete them after they are fired off)

            //Go through the list and reschedule them

            #endregion

            sWakeLock.Release();
            return;
        }

        #endregion

        string notificationtype = intent.GetStringExtra("notificationtype");

        Intent startupIntent = Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
        startupIntent.PutExtra("notificationtype", notificationtype);

        // Instantiate the builder and set notification elements, including pending intent:
        Notification.Builder builder = new Notification.Builder(Application.Context)
            .SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
            .SetAutoCancel(true)
            .SetContentIntent(PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot))
            .SetContentTitle("Sample Notification")
            .SetContentText("Hello World! This is my first action notification!")
            .SetTicker("New Notification")
            .SetSmallIcon(Resource.Drawable.icon);

        // Build the notification:
        Android.App.Notification notification = builder.Build();

        // Get the notification manager:
        NotificationManager notificationManager = Application.Context.GetSystemService(Context.NotificationService) as NotificationManager;

        // Publish the notification:
        int notificationId = ??;//This should be a real unique number, otherwise it can cause problems if there are ever multiple scheduled notifications
        notificationManager.Notify(notificationId, notification);
    }
}
}

关于xamarin - 在 Xamarin Forms Android 中处理通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43936784/

相关文章:

android - InstantiationException:无法实例化 fragment 确保类名存在,是公共(public)的,并且有一个空的公共(public)构造函数

ios - ios(Xamarin)中的奇怪行为UIButton

c# - Xamarin Android Designer 显示黑屏而不是应用程序界面

xamarin - 如何在xamarin.forms中显示使用Page.Is Busy?

c# - Java.Interop.Tools.Diagnostics.XamarinAndroidException : error XA2006

android - Xamarin Android SDK 位置

c# - Xamarin 固定导航栏

c# - 如何在 xamarin 中添加 System.Drawing?

android - 自定义 ListView 适配器显示不正确的值 [Mono Android]

c# - 如何为 Xamarin.forms 实现 Lottie?