Forum Xamarin Xamarin.Android

Statically registering a Broadcast Receiver - A working example

FullMetalJacobFullMetalJacob Member ✭✭
edited January 2019 in Xamarin.Android

Hello there

I wan't to statically register a Broadcast Receiver and I have followed the guidelines at
https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/broadcast-receivers

As I understand we do not register the Broadcast Receiver directly in the Android Manifest file, but instead we decorate our receiver as following

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "com.xamarin.example.TEST" })]
public class MySampleBroadcastReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        Console.WriteLine("Hurray it works"!);
    }
}

Then the receiver should be able to pick up on the following broadcast

Intent message = new Intent("com.xamarin.example.TEST");
SendBroadcast(message);

However I do not receive this intent. I only receive the intent, when I register the receiver within the context as following

RegisterReceiver(new MySampleBroadcastReceiver(), new IntentFilter("com.xamarin.example.TEST"));

Have I misunderstood something or am I missing some steps? Any help would be appreciated.

Why do I need this?
My goal is to launch notifications at particular timestamps defined by the user. I've context-registered a broadcast receiver, that issues a notification, when an intent is received. The Android Alarm Manager is used to broadcast the intent at a particular time.
As the broadcast receiver is context-registered it will not receive intents, when the app has been killed (when the app is swiped in the recent applications menu). I want the notifications to keep coming when the app has been swiped.

Best Answer

  • FullMetalJacobFullMetalJacob Member ✭✭
    Accepted Answer

    I was successful at registering the mentioned Broadcast Receiver statically by adding the following to the Android Manifest file

    <receiver android:name=".MySampleBroadcastReceiver"/>

    To anyone reading this discussion I will also point out that I do not recommend this approach as it will not work if your project targets API level 26+ and the device API version is 26+

    This is how I registered a Broadcast Receiver that keeps running if the app is closed

    I had success will all API levels tested using a Service instead.

    I created a new Service class

    [Service]
    public class NotificationService : Service
    {
        private static BroadcastReceiver notificationReceiver;
    
        public override IBinder OnBind(Intent intent)
        {
            return null;
        }
    
        public override void OnCreate()
        {
            RegisterBroadcastReceiver();
        }
    
        public override void OnDestroy()
        {
            Application.Context.UnregisterReceiver(notificationReceiver);
            notificationReceiver = null;
        }
    
        private void RegisterBroadcastReceiver()
        {
            notificationReceiver = new MySampleBroadcastReceiver();
    
            IntentFilter filter = new IntentFilter("com.xamarin.example.TEST");
            Application.Context.RegisterReceiver(notificationReceiver, filter);
        }
    }
    

    I registered the Service in the Android Manifest file within the Application tag

    <service android:name=".NotificationService"/>

    And finally I started the Service from the MainActivity

    Intent service = new Intent(this, typeof(NotificationService));
    StartService(service);
    

    Now the Broadcast Receiver stays active even when the app has been closed

Answers

  • jezhjezh Member, Xamarin Team Xamurai

    I created a new app and copied your code to reproduce the problem , but it worked well.
    Besides,However I do not receive this intent. I only receive the intent, when I register the receiver within the context as following... what do you mean by this?

  • Hello Jezh, thank you for your attention!

    What I mean by the mentioned statement is that the OnReceive method is not called, when I broadcast the intent.

    I have attempted to create a minimal working example project, where I experience that the OnReceive method is not called as well. Maybe we can compare our differences?

    The Main Class:

    using System;
    using Android.App;
    using Android.Content;
    using Android.OS;
    using Android.Support.Design.Widget;
    using Android.Support.V7.App;
    
    namespace StaticBroadcastOne
    {
        [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
        public class MainActivity : AppCompatActivity
        {
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                SetContentView(Resource.Layout.activity_main);
    
                Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
                SetSupportActionBar(toolbar);
    
                FloatingActionButton fab = FindViewById<FloatingActionButton>(Resource.Id.fab);
                fab.Click += FabOnClick;
            }
    
            private void FabOnClick(object sender, EventArgs eventArgs)
            {
                Console.WriteLine("Button clicked");
                Intent message = new Intent("com.xamarin.example.TEST");
                SendBroadcast(message);
            }
        }
    }
    

    The BroadcastReceiver class

    using System;
    using Android.App;
    using Android.Content;
    
    namespace StaticBroadcastOne
    {
        [BroadcastReceiver(Enabled = true)]
        [IntentFilter(new[] { "com.xamarin.example.TEST" })]
        public class MySampleBroadcastReceiver : BroadcastReceiver
        {
            public override void OnReceive(Context context, Intent intent)
            {
                Console.WriteLine("Hurray it works!");
            }
        }
    }
    

    Maybe you can reference your project for me to inspect further?

    Best regards!

  • jezhjezh Member, Xamarin Team Xamurai

    Have you registered the BroadcastReceiver as follows?

    RegisterReceiver(new MySampleBroadcastReceiver(), new IntentFilter("com.xamarin.example.TEST"));
    

    The main code is:
    MainActivity.cs

      [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {
        Button goButton;
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);
            goButton = FindViewById<Button>(Resource.Id.goBtn);
    
            goButton.Click += GoButton_Click;
    
            RegisterReceiver(new MySampleBroadcastReceiver(), new IntentFilter("com.xamarin.example.TEST"));
        }
    
        private void GoButton_Click(object sender, System.EventArgs e)
        {
            Intent message = new Intent("com.xamarin.example.TEST");
            SendBroadcast(message);
        }
    }
    

    MySampleBroadcastReceiver.cs

     [BroadcastReceiver(Enabled = true)]
    [IntentFilter(new[] { "com.xamarin.example.TEST" })]
    public class MySampleBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            if (intent!=null) {
            Console.WriteLine("Hurray it works");
            }
        }
    }
    

    My project is in the attachment you can check.

  • I did not register the BroadcastReceiver in the code as you pointed out.

    Let me share my thoughts as I may have misunderstood something you can point out to me. :)

    There are two ways of registering a BroadcastReceiver - dynamically/context-registering (directly in code as in your example) and statically

    When building an application in Android Studio that corresponds to registering the BroadcastReceiver in the Android Manifest file (statically) and registering it inside an activity (dynamically/context-registering)

    In the link below they discuss the differences between registering in manifest vs in an activity
    https://stackoverflow.com/questions/10876015/broadcast-receiver-register-in-manifest-vs-activity

    As responded by Nikolay Elenkov in the thread:
    If your receiver is registered in the manifest, and your app is not running, a new process will be created to handle the broadcast. If you register it in code, it's tied to the life of the activity/service you registered it in...

    However in Xamarin you will not add code into the Android Manifest file yourself to statically register a BroadcastReceiver.

    As explained in the docs:
    When a BroadcastReceiver is decorated with the IntentFilterAttribute, Xamarin.Android will add the necessary <intent-filter> element to the Android manifest at compile time.

    https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/broadcast-receivers

    I might be wrong in the way I have interpreted the discussions and docs. Thanks for your help!

  • FullMetalJacobFullMetalJacob Member ✭✭
    Accepted Answer

    I was successful at registering the mentioned Broadcast Receiver statically by adding the following to the Android Manifest file

    <receiver android:name=".MySampleBroadcastReceiver"/>

    To anyone reading this discussion I will also point out that I do not recommend this approach as it will not work if your project targets API level 26+ and the device API version is 26+

    This is how I registered a Broadcast Receiver that keeps running if the app is closed

    I had success will all API levels tested using a Service instead.

    I created a new Service class

    [Service]
    public class NotificationService : Service
    {
        private static BroadcastReceiver notificationReceiver;
    
        public override IBinder OnBind(Intent intent)
        {
            return null;
        }
    
        public override void OnCreate()
        {
            RegisterBroadcastReceiver();
        }
    
        public override void OnDestroy()
        {
            Application.Context.UnregisterReceiver(notificationReceiver);
            notificationReceiver = null;
        }
    
        private void RegisterBroadcastReceiver()
        {
            notificationReceiver = new MySampleBroadcastReceiver();
    
            IntentFilter filter = new IntentFilter("com.xamarin.example.TEST");
            Application.Context.RegisterReceiver(notificationReceiver, filter);
        }
    }
    

    I registered the Service in the Android Manifest file within the Application tag

    <service android:name=".NotificationService"/>

    And finally I started the Service from the MainActivity

    Intent service = new Intent(this, typeof(NotificationService));
    StartService(service);
    

    Now the Broadcast Receiver stays active even when the app has been closed

  • BasitBasit Member
    edited January 7

    @FullMetalJacob i tried your code but onrecieve method of MySampleBroadcastReceiver is never triggered ... Actually a i want to use broadcast to decect when a phone state is ringing i.e for incoming call ... i used android.intent.action.PHONE_STATE as the intent for same code as yours just intent replaced but is not running can you guide me please i m stuck at this for days now ... also for your code as it is the onreceive method of broadcast is never triggered then how would i know that broadcast is running ... i am very new in xamarin android forms so please guide me...

  • d0naldashw0rthd0naldashw0rth Member ✭✭
    edited March 31

    Hello. I am having the exact same problem as mentioned in this thread: My statically registered Android BroadcastReceiver is not auto-starting after rebooting my device and having issued my custom Intent ("MY_SPECIFIC_ACTION").

    I am using Visual Studio 2019 host on PC Windows 10. My min Android version is API Level 20 - Kit Kat) and my target framework is set to Android 9.0 (Pie).

    I have attached my Visual Studio 2019 solution to this post.

    So, I have been suffering with this for a week. My goal is to create an Android app that is started upon device reboot (monitoring BOOT_COMPLETED and QUICKBOOT_POWERON intents). I believe I have followed implementation recommendations correctly. Even samples that I have found are not demonstrating wake-on-boot app functionality.

    I have decorated my BootReceiver class with the appropriate attributes...

    [BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true, Permission = "android.permission.RECEIVE_BOOT_COMPLETED")]
    [IntentFilter(new[] { "MY_SPECIFIC_ACTION", "android.intent.action.BOOT_COMPLETED", "android.intent.action.QUICKBOOT_POWERON" },
    Categories = new[] { "android.intent.category.DEFAULT" })]

    ...and always have requested the required device permissions within the MainActivity...
    static readonly int RC_REQUEST_LOCATION_PERMISSION = 1000;

        static readonly string[] REQUIRED_PERMISSIONS = { 
            Android.Manifest.Permission.ReceiveBootCompleted, 
            Android.Manifest.Permission.AccessCoarseLocation, 
            Android.Manifest.Permission.AccessFineLocation  };
    

    ActivityCompat.RequestPermissions(this, REQUIRED_PERMISSIONS, RC_REQUEST_LOCATION_PERMISSION);

    I have read about Oreo tightening down security and also RECEIVE_BOOT_COMPLETED and BOOT_COMPLETED are not included in the System intent exclusions.

    Has anyone been able to achieve wake-on-boot app functionality?

Sign In or Register to comment.