在Xamarin Forms Android中处理通知

Ray*_*lon 2 xamarin.android android-notifications xamarin xamarin.forms

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

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

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

 protected override void OnNewIntent(Intent intent)
    {

    }
Run Code Online (Sandbox Code Playgroud)

但是,我无法从通知中找到任何意图来建立到特定页面的导航的信息。

任何意见,将不胜感激。

干杯!

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

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

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

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();



        }
    }
Run Code Online (Sandbox Code Playgroud)

关闭应用程序后,如何使我的广播接收器保持活动状态?

hva*_*an3 6

好的,所以我花了一些时间才弄清楚这一点。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);
    }
Run Code Online (Sandbox Code Playgroud)

要查看如何向其中添加数据,Intent可以查看Xamarin Sport App,但不要像我一直倾向于做的那样对他们正在执行的所有其他工作感到困惑。只专注于PutExtra一部分。

编辑#1:

如果您的应用程序完全关闭,则需要从Intent传入的数据中提取数据OnCreate并将其传递到您的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
}
Run Code Online (Sandbox Code Playgroud)

编辑#2:

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

  • 标记您的广播接收器
  • 添加愚蠢的Xamarin构造函数
  • 使用IntentFilter的常量属性代替字符串
  • 删除IntentFilter优先级
  • 检查是否有空意图(可能没有必要)
  • 使用Application.Context而不是Forms.Context(我在应用程序的其他部分中使用Forms.Context,因此不确定这一点,但不会造成伤害)
  • 不要覆盖Intent中传递的内容
  • 创建启动意图而非常规
  • 在添加额外内容之前添加IncludeStoppedPackages标志
  • 检查启动完成事件
  • 使用Notification.Builder而不是NotificationCompat.Builder(尽管您可能需要将其改回)
  • 将以下标志添加到未决意图:PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot-使用NotificationManager(除非您有特定原因将其注释掉)
[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);
    }
}
}
Run Code Online (Sandbox Code Playgroud)