0

I am working on xamarin.forms app and I am setting local notification using alarm manager. It is triggering fine on android version 8 and 9 but somehow it's not triggering in Android 10.

In android device logs for Android 10, I got

07-22 15:00:06.612  Samsung SM-M205F    Verbose 4185    SamsungAlarmManager Sending to uid : 10244 action=null alarm=Alarm{a757a70 type 0 when 1595410200000 com.MyApp.andr.connect}

07-22 15:00:06.613  Samsung SM-M205F    Warning 4185    BroadcastQueue  Unable to launch app com.MyApp.andr.connect/10244 for broadcast Intent { flg=0x14 cmp=com.MyApp.andr.connect/crc640e87e93c5dbd1629.AlarmReceiver (has extras) }: process is bad

Update (Issue is still with Android 10)

I have managed to get notification when app is running, but now notifications are not firing when app is closed.

Note : I have made a sample which is working just fine with Android 10, Notifications are triggering when app is running or closed in the sample. I don't have to use foreground service. (I have used same approach in my work project). So There is something wrong in my work project which I am not able to figure out.

Here is the Android device logs when app is closed and notifications are about to trigger,

enter image description here If someone can help !

Dhruv Gohil
  • 503
  • 1
  • 5
  • 13

1 Answers1

0

All of the code will be frozen when your application is closed including the alarm manager. If you want it still alive, we could use foreground service: https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/services/foreground-services This may be a little out of date, here is my approach to create the notification:

[Service]
public class SampleService : Service
{
    public static string CHANNEL_ID = "com.channelid";
    public static string CHANNEL_NAME = "com.channelname";
    public override void OnCreate()
    {
        base.OnCreate();

           
    }

    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        registerNotificationChannel();
        int notifyId = (int)JavaSystem.CurrentTimeMillis();
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
        mBuilder.SetSmallIcon(Resource.Mipmap.ic_launcher);
        if (Build.VERSION.SdkInt < BuildVersionCodes.N)
        {
            mBuilder.SetContentTitle("app name");
        }
        StartForeground(notifyId, mBuilder.Build());
        return StartCommandResult.Sticky;
    }

    private void registerNotificationChannel()
    {
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            NotificationManager mNotificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
            NotificationChannel notificationChannel = mNotificationManager.GetNotificationChannel(CHANNEL_ID);
            if (notificationChannel == null)
            {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                        CHANNEL_NAME, NotificationImportance.High);
                channel.EnableLights(true);
                channel.LightColor = Color.Red;
                channel.LockscreenVisibility = NotificationVisibility.Public;
                mNotificationManager.CreateNotificationChannel(channel);
            }
        }
    }

    public override IBinder OnBind(Intent intent)
    {
        throw new NotImplementedException();
    }
}

Update

Now you don't need to use alarmmanager any more .

In MainActivity

 public static MainActivity Instance { get; set; }
 protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;
      
        base.OnCreate(savedInstanceState);

        Instance = this;

        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App());
    }

In AlarmAndNotificationService

void IAlarmAndNotificationService.ScheduleLocalNotification(string notificationTitle, string notificationMessage, DateTime specificDateTime, TimeSpan timeSpan, int notificationId, NotificationInterval interval)
{
   // start service here 
   Intent s = new Intent(MainActivity.Instance, typeof(SampleService));

   MainActivity.Instance.StartService(s);
}

in SampleService

 public class SampleService : Service
{
    private Handler handler;
    private Action runnable;
    private bool isStarted;
    private int DELAY_BETWEEN_LOG_MESSAGES = 5000;  // set time span 
    private int NOTIFICATION_SERVICE_ID = 1001;
    private int NOTIFICATION_AlARM_ID = 1002;
    private string NOTIFICATION_CHANNEL_ID = "1003";
    private string NOTIFICATION_CHANNEL_NAME = "MyChannel";
    public override void OnCreate()
    {
        base.OnCreate();

        handler = new Handler();


        //here is what you want to do always, i just want to push a notification every 5 seconds here
        runnable = new Action(() =>
        {
            if (isStarted)
            {
                DispatchNotificationThatAlarmIsGenerated("I'm running");
                handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
            }
        });
    }

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        if (isStarted)
        {
            // service is already started
        }
        else
        {
            CreateNotificationChannel();
            DispatchNotificationThatServiceIsRunning();

            handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
            isStarted = true;
        }
        return StartCommandResult.Sticky;
    }

    public override void OnTaskRemoved(Intent rootIntent)
    {
        //base.OnTaskRemoved(rootIntent);
    }

    public override IBinder OnBind(Intent intent)
    {
        // Return null because this is a pure started service. A hybrid service would return a binder that would
        // allow access to the GetFormattedStamp() method.
        return null;
    }

    public override void OnDestroy()
    {
        // Stop the handler.
        handler.RemoveCallbacks(runnable);

        // Remove the notification from the status bar.
        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.Cancel(NOTIFICATION_SERVICE_ID);

        isStarted = false;
        base.OnDestroy();
    }

    private void CreateNotificationChannel()
    {
        //Notification Channel
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Max);
        notificationChannel.EnableLights(true);
        notificationChannel.EnableVibration(true);
        notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });


        NotificationManager notificationManager = (NotificationManager)this.GetSystemService(Context.NotificationService);
        notificationManager.CreateNotificationChannel(notificationChannel);
    }

    //start a foreground notification to keep alive 
    private void DispatchNotificationThatServiceIsRunning()
    {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
               .SetDefaults((int)NotificationDefaults.All)
               .SetSmallIcon(Resource.Drawable.icon)
               .SetVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
               .SetSound(null)
               .SetChannelId(NOTIFICATION_CHANNEL_ID)
               .SetPriority(NotificationCompat.PriorityDefault)
               .SetAutoCancel(false)
               .SetContentTitle("Mobile")
               .SetContentText("My service started")
               .SetOngoing(true);

        NotificationManagerCompat notificationManager = NotificationManagerCompat.From(this);
        StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
    }

    //every 5 seconds push a notificaition
    private void DispatchNotificationThatAlarmIsGenerated(string message)
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);
        var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);

        Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
            .SetSmallIcon(Resource.Drawable.icon)
            .SetContentTitle("Alarm")
            .SetContentText(message)
            .SetAutoCancel(true)
            .SetContentIntent(pendingIntent);

        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.Notify(NOTIFICATION_AlARM_ID, notificationBuilder.Build());
    }
}
Lucas Zhang
  • 18,630
  • 3
  • 12
  • 22
  • I am not getting notification even when app is running in foreground. – Dhruv Gohil Jul 15 '20 at 11:33
  • You could test the app on another device (or emulator) . There will maybe some unknown issue on some specific device. – Lucas Zhang Jul 16 '20 at 06:52
  • I have managed to get notification when app is running using BroadcastReceiver. but it is not firing when app is closed. So I think above solution can help. Do I need BroadcastReceiver if I use ForegroundService to trigger notifications and How can I set notifications to trigger at specific date and time ? – Dhruv Gohil Jul 18 '20 at 10:35
  • Of course `BroadcastReceiver` is still necessary . For how to start a service at specific time , you could check https://stackoverflow.com/questions/39092274/alarm-manager-set-daily-alarm-at-a-specific-time – Lucas Zhang Jul 20 '20 at 07:03
  • I have made a sample project of triggering local notification using alarmmanager and it works just fine when app is running and closed. I don't even have to use foreground service in the sample project. So it may be some other issue on my work project. I will give update here when I resolve issue in my work project. – Dhruv Gohil Jul 20 '20 at 09:13
  • Lucas Zhang - MSFT - I have updated my question, If you can help or give any suggestion. – Dhruv Gohil Jul 23 '20 at 03:56
  • Could you share you sample so that I can test it on my side . – Lucas Zhang Jul 23 '20 at 09:57
  • Lucas Zhang - MSFT - Here is the sample : https://github.com/dhruvgohiloo7/NotificationsWithAlarmManager – Dhruv Gohil Jul 26 '20 at 14:14
  • OK , I will check it . – Lucas Zhang Jul 27 '20 at 07:20
  • Check https://github.com/xamarin/monodroid-samples/blob/master/ApplicationFundamentals/ServiceSamples/ForegroundServiceDemo/TimestampService.cs . You don't need to use BroadcastReceiver any more . You just need to put the logic of send notification and upload location in `runnable` – Lucas Zhang Jul 27 '20 at 08:33
  • You could also check https://stackoverflow.com/questions/60028587/background-service-with-isolated-process-in-xamarin-forms/60032046#60032046 . The code provided by Leo will send a notification every 5 seconds. – Lucas Zhang Jul 27 '20 at 08:38
  • Lucas Zhang - MSFT - Thanks for reply, Do I need alarmmanager and where should I set alarm ? – Dhruv Gohil Jul 30 '20 at 04:53
  • Check my update answer , if it is helps you , don't forget to accept my answer :) – Lucas Zhang Jul 30 '20 at 07:14
  • Thanks, I will try it, but I have a question : sample project that I have provided is working fine with android 10 and doesn't need to add foreground service then why do I need to add it to my main project as I have a same code in main project as sample project to trigger notification.? – Dhruv Gohil Jul 30 '20 at 08:49
  • On some specific device it is necessary . – Lucas Zhang Jul 30 '20 at 08:51
  • I run sample project on same device and it is working – Dhruv Gohil Jul 30 '20 at 08:52
  • As I said on some special device . – Lucas Zhang Jul 30 '20 at 08:58
  • I am looking into above code, but I am not getting how can I set notifications for e.g. : Notification 1 - which triggers everyday at 12 pm, Notification 2 - which will trigger from 1st aug to 5 aug at 3 pm, and Notification 3 - which will trigger from 1st aug to 10 aug at 4 pm – Dhruv Gohil Jul 31 '20 at 07:00
  • one more thing I noticed that, foreground notification can not be removed, is it possible to hide or remove ? – Dhruv Gohil Aug 03 '20 at 04:53
  • Lucas Zhang - MSFT - foreground notification can not be removed, is it possible to hide or remove ? – Dhruv Gohil Aug 10 '20 at 11:04