Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

xamarin - AlarmManager and Notifications in Android 8.0(Oreo)

In my app i have a alarm that is repeting every thursday, i am using AlarmManger, everything is working fine in all previous versions of android, but now with android 8.0(oreo), the alarm Isn't firing, below is the classes that i use to set my alarm. From what i searched i need to set the alarm explicitly, but I dont understand how.

MainActivity:

try
        {
            Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
            PendingIntent pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
            AlarmManager alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();

            if (Settings.AccessAlarm == 0)
            {
                alarmManager.SetRepeating(AlarmType.RtcWakeup, BootReceiver.FirstReminder(), BootReceiver.reminderInterval, pending);
                PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, 0);
                Settings.AccessAlarm = 1;
            }
        }
        catch (Exception e)
        {
            Settings.AccessAlarm = 0;
        }

Bootreceiver.cs:

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
    //the interval currently every one minute
    //to set it to dayly change the value to 24 * 60 * 60 * 1000
    public static long reminderInterval = AlarmManager.IntervalDay * 7;
    //public static long reminderInterval = 3 * 1000;

    public static long FirstReminder()
    {
        System.Random rnd = new System.Random();

        int minutenumber = rnd.Next(20, 40);

        Java.Util.Calendar calendar = Java.Util.Calendar.Instance;
        calendar.Set(Java.Util.CalendarField.DayOfWeek, Calendar.Thursday);
        calendar.Set(Java.Util.CalendarField.HourOfDay, 10);
        calendar.Set(Java.Util.CalendarField.Minute, minutenumber);
        return calendar.TimeInMillis;

    }

    public override void OnReceive(Context context, Intent intent)
    {
        try
        {
            Console.WriteLine("BootReceiver: OnReceive");
            var alarmIntent = new Intent(context, typeof(AlarmReceiver));
            var pending = PendingIntent.GetBroadcast(context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
            AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
            alarmManager.SetRepeating(AlarmType.RtcWakeup, FirstReminder(), reminderInterval, pending);

            PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
            Settings.AccessAlarm = 1;
        }
        catch (Exception e)
        {
            Settings.AccessAlarm = 0;
        }

    }
}

AlarmReceiver:

[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
    private int z = 0;
    private int i;


    public override void OnReceive(Context context, Intent intent)
    {
        try
        {
                Settings.AlarmNotification = 1;

                if (System.DateTime.Now.DayOfWeek == DayOfWeek.Thursday)
                {
                    Settings.AlarmCount =0;
                }

                var title = "Test";
                var message = "Something";

                Intent backIntent = new Intent(context, typeof(MainActivity));
                backIntent.SetFlags(ActivityFlags.NewTask);



                var resultIntent = new Intent(context, typeof(MainActivity));



                PendingIntent pending = PendingIntent.GetActivities(context, 0,
                    new Intent[] { backIntent, resultIntent },
                    PendingIntentFlags.OneShot);

                var builder =
                    new Notification.Builder(context)
                        .SetContentTitle(title)
                        .SetContentText(message)
                        .SetAutoCancel(true)
                        .SetSmallIcon(Resource.Drawable.icon)
                        .SetDefaults(NotificationDefaults.All);

                builder.SetContentIntent(pending);
                var notification = builder.Build();
                var manager = NotificationManager.FromContext(context);
                manager.Notify(1331, notification);

        }
        catch (Exception)
        {

        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your alarms would be firing correctly as you are using explicit intents. But in Oreo/API26 .SetDefaults(NotificationDefaults.All is obsolete and will cause a silent failure and your notifications will not be displayed.

So you need to setup a notification channel to properly display your notification with all the bells and whistles.

If you replace your notification builder & notify code:

var builder =
    new Notification.Builder(context)
        .SetContentTitle(title)
~~~~
manager.Notify(1331, notification);

With an API check for Oreo/API26(+) you can established an notification channel for your app:

using (var notificationManager = NotificationManager.FromContext(context))
{
    Notification notification;
    if (Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
    {
        notification = new Notification.Builder(context)
                                    .SetContentTitle(title)
                                    .SetContentText(message)
                                    .SetAutoCancel(true)
                                    .SetSmallIcon(Resource.Drawable.icon)
                                    .SetDefaults(NotificationDefaults.All)
                                    .SetContentIntent(pending)
                                    .Build();
    }
    else
    {
        // Setup a NotificationChannel, Go crazy and make it public, urgent with lights, vibrations & sound.
        var myUrgentChannel = context.PackageName;
        const string channelName = "SushiHangover Urgent";

        NotificationChannel channel;
        channel = notificationManager.GetNotificationChannel(myUrgentChannel);
        if (channel == null)
        {
            channel = new NotificationChannel(myUrgentChannel, channelName, NotificationImportance.High);
            channel.EnableVibration(true);
            channel.EnableLights(true);
            channel.SetSound(
                RingtoneManager.GetDefaultUri(RingtoneType.Notification),
                new AudioAttributes.Builder().SetUsage(AudioUsageKind.Notification).Build()
            );
            channel.LockscreenVisibility = NotificationVisibility.Public;
            notificationManager.CreateNotificationChannel(channel);
        }
        channel?.Dispose();

        notification = new Notification.Builder(context)
                                    .SetChannelId(myUrgentChannel)
                                    .SetContentTitle(title)
                                    .SetContentText(message)
                                    .SetAutoCancel(true)
                                    .SetSmallIcon(Resource.Drawable.icon)
                                    .SetContentIntent(pending)
                                    .Build();
    }
    notificationManager.Notify(1331, notification);
    notification.Dispose();
}

Now in settings, your app has a channel assigned to it that the user can customize if they so choose:

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...