7

I am trying to make a simple service which starts with device boot. Thing is that device return message "Unfortunately, [app_name] has stopped."

I am struggling with this problem from few hours, with looking for mistake, but it is too simple.. Hope, you guys can help me with this problem.

This is my code:

AndroidManifest.xml

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application android:allowBackup="true" android:label="@string/app_name">


    <receiver android:name=".StartReceiver">
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED"/>
          </intent-filter>
    </receiver>

  <service android:name=".PService" />
</application>

StartReceiver.cs

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class StartReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        Intent startIntent = new Intent(context, typeof(PService));
        context.StartService(startIntent);
    }
}

and lastly PService.cs

[Service]
    public class PService : Service
    {
        public override void OnCreate()
        {
            base.OnCreate();
        }

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }


        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            Toast.MakeText(this, "Start", ToastLength.Short).Show();
            return StartCommandResult.Sticky;
        }

        public override void OnDestroy()
        {
            base.OnDestroy(); 

            Toast.MakeText(this, "Stop", ToastLength.Short).Show();
        }
    }

Additional this service application is targetted to API 19 (4.4.2 KitKat) Android version.

I think there will be really small mistake, made by me but truly I cant find it out.. Thanks in advance for any help.

Grzegorz G.
  • 1,285
  • 2
  • 14
  • 27
  • In order to be able to catch BOOT_COMPLETED intent, you app should also have UI and your user should open the App at least once. - for security reasons. – EvZ Mar 21 '18 at 10:40
  • yes I have Activity class where i Start an service. (Service starts normally) problem is after reboot the device – Grzegorz G. Mar 21 '18 at 10:55

3 Answers3

11

By adding the receiver in the manifest and via the BroadcastReceiverAttribute you have two receivers in your manifest. Plus the one in your manifest will not work since it is not the MD5-based Java name that Xamarin creates by default.

Via Attributes

1) Remove the receiver and boot permission from your manifest

2) Add your boot permissions via an attribute)

[assembly: UsesPermission(Manifest.Permission.ReceiveBootCompleted)]

3) Add the manifest entry via attributes:

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Intent.ActionBootCompleted })]    
public class BootBroadcastReceiver : BroadcastReceiver

Via manifest

1) Add the manifest entry for the boot permission

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

2) Add the receiver and use a full qualify Java class name:

<receiver android:name="com.yourpackagename.app.BootBroadcastReceiver">
      <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
</receiver>

3) Add a Name parameter to the BroadcastReceiverAttribute for the fully qualified Java class name that you used in the manifest

[BroadcastReceiver(Name = "com.yourpackagename.app.BootBroadcastReceiver", Enabled = true)]
[IntentFilter(new[] { Intent.ActionBootCompleted })]    
public class BootBroadcastReceiver : BroadcastReceiver
SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • Thank you Sushi,the method 'Via manifest' worked for me well. – Grzegorz G. Mar 26 '18 at 08:33
  • 1
    @CDrosos Post a new question with your problem as I know this works on 7.0 (all APIs in fact) – SushiHangover Jun 07 '18 at 21:26
  • is that intent filter necessary? I mean asking about general BroadcastReceiver should we define an intent filter or just for this case because of OP wrote in his question. I mean in the via Manifest soltution. you define intent filter in manifest and as well as as an attribute? is it not double? – Emil Sep 23 '19 at 22:04
  • 1
    @batmaci In "Step 3" of the manifest solution, you have to define a `Name` attribute for the "fully qualified Java class" that you are defining in the manifest manually, so making them match actually removes removes the issue of an "double" additions (It is possible since I last checked that Xamarin's build process properly merges manifest changes, you would need to test that yourself) – SushiHangover Sep 23 '19 at 22:51
  • com.yourpackagename.app?? Is that whole package name? Must you add a .app? – user1034912 Jan 10 '22 at 12:42
  • Ok 2022 this does not work anymore!!! – user1034912 Jan 10 '22 at 14:38
1

There are a few gotchas I faced when working on this:

  1. Android ignores broadcast receivers of applications that have never been started by the user. When deploying using Visual Studio, your app is installed fresh and started automatically which doesn't satisfy the "user-started" condition so your Broadcast Receiver won't get the ACTION_BOOT_COMPLETED intent. You will need to close the app after deployment (I remove it from my Recent Apps list) and manually re-open it again before it begins to receive implicit intent. This tripped me up tremendously and I had spent several hours till I came across someone else who discovered this.

  2. If you're using Xamarin Forms, make sure you're not using DependencyService.Get() in your Broadcast Receiver as that requires Xamarin Forms to be initialized but the Android system doesn't call your MainActivity when triggering your BroadcastReceiver. The result is that the BroadcastReceiver does in fact get started but because it throws an Exception, you might not realize that it got called at all. I suggest using the Android implementation of the DI service directly in these cases.

Other than that, my BroadcastReceiver was pretty standard:

[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new[] { Intent.ActionLockedBootCompleted })]
public class RebootReceiver : BroadcastReceiver

I receive the ACTION_LOCKED_BOOT_COMPLETED intent which is broadcast earlier than the ACTION_BOOT_COMPLETED but requires the DirectBootAware property to be enabled and has some more specific limits regarding its usage. According to your needs, Intent.ActionBootCompleted without the DirectBootAware property could be just as sufficient.

And my Assembly.info file included this:

[assembly: UsesPermission(Android.Manifest.Permission.ReceiveBootCompleted)]
frezq
  • 653
  • 8
  • 18
  • Point 1 (starting the app manually at least once) does indeed seem to be required now before my app's broadcast receiver could be started on Android v13 (API level 33), thanks! – Netricity Mar 09 '23 at 13:54
0

2022 ANSWER

After almost 3 hours banging my head on the wall, I finally got it to work. All answers are out dated since Google made a few API changes. Anyway, here is what worked for me.

How I tested

  1. Launch App on phone (Just to clear out any confusions, I even launched it using my debugger to confirm it was not due to 'debug' mode). Fyi, I am using Xiaomi Pocophone F1. My App is targeting API level 30.
  2. Make the App schedule notifications to appear 3 minutes later
  3. Reboot the phone
  4. Wait for 3 minutes (Note that I am NOT launching my App. I also do not have App autostart permission enabled for me. There was some old answer suggesting autostart must be on. This is WRONG i.e. not required)
  5. After 3 minutes the notification appears! This means during reboot the Boot BroadcastReceiver fired up.

The code

[assembly: UsesPermission (Manifest.Permission.ReceiveBootCompleted)]
namespace MyApp.Droid
{
    [BroadcastReceiver(Name = "com.myapp.whatever.BootReceiver", Enabled = true)]
    [IntentFilter(new[] { Intent.ActionBootCompleted })]    
    public class BootReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            RescheduleNotifications();
        }

        public void RescheduleNotifications()
        {
            try
            {
                AppCenter.Start("android=cfc33334-8f5e-4ab3-1232-e8712345c860;"
                    //"ios={Your iOS App secret here}",
                    , typeof(Crashes));
                
                //Make sure all services are instantiated
                AppCore.DeviceService = new DeviceService();
                AppCore.FbService = new FBService();
                AppCore.AppService = new AppService();
                AppCore.DeviceService.ScheduleNotifications(notif.Notifications, false);
            }
            catch (Exception e)
            {
                Crashes.TrackError(e);
            }
        
        }
    }
}

Notes on my code

  • I am using MS App Center to track crashes. You may omit these parts.
  • Remember that the OnReceive is fired alone (without Main Activity being fired). So make sure your code can run and does not throw any exceptions.
  • In "com.myapp.whatever.BootReceiver" replace "com.myapp.whatever" with your app's package name

The android manifest

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<application ....>
<receiver android:enabled="true" android:name="com.myapp.whatever.BootReceiver" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>
    </application>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
user1034912
  • 2,153
  • 7
  • 38
  • 60
  • I'm trying this approach, how do I find out my "app's package name" that I need to replace "com.myapp.whatever" with? Is it some combination of the Visual Studio project name (AutoStartupApp in my case), and C# class name? Do I need to include the C# namespace as well? – Netricity Mar 03 '22 at 09:56
  • Don't know why this was -1. After days of trying everything, this is what worked in 2022. – Joginder Tanikella Mar 28 '22 at 20:35
  • 2
    @Netricity The Package Name is there in your Android Project's properties. – Joginder Tanikella Mar 28 '22 at 20:37
  • Thanks for the solution. But I don't understand what is this: "android=cfc33334-8f5e-4ab3-1232-e8712345c860;". Where could I find this code? Thanks. – Álvaro García May 06 '23 at 11:56
  • if it is not needed to setup autostart to start in a reboot, how could I let to the user to decide if he wants to start the application on power on or not? I would like to have give the option to can configure this behavior. Thanks. – Álvaro García May 10 '23 at 07:58
  • In which namespace is AppCore? – Álvaro García May 10 '23 at 08:04