9

I have to receive system-sent implicit broadcasts (ACTION_PACKAGE_ADDED) to detect the installation of the application and perform some code. I used the code below:

public class Receiver extends BroadcastReceiver{
   @Override
   public void onReceive(Context context, Intent intent) {
     // It will trigger when any app is installed           
        Uri data = intent.getData();
        String packageAdv = data.getEncodedSchemeSpecificPart();
     //some code...
   }
}

In my Manifest file I declared my receiver:

<receiver android:name="com.myapp.Receiver">
        <intent-filter>                    
           <action android:name="android.intent.action.PACKAGE_ADDED" />                        
           <data android:scheme="package"/> 
        </intent-filter>
</receiver> 

It works perfect before Version 8.0 Oreo. Now, I have to make my receiver explicit by using registerReceiver. How can I do this? Sample code would be appreciated.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Nolesh
  • 6,848
  • 12
  • 75
  • 112
  • Version 8.0 Oreo have deprecated this function. – KuLdip PaTel Mar 19 '18 at 12:12
  • 1
    have look [this](https://stackoverflow.com/a/45996525/5110595) – Hemant Parmar Mar 19 '18 at 12:13
  • Step #1: Create a foreground `Service`. Step #2: In `onCreate()` of that service, call `registerReceiver()`, passing in an instance of your `BroadcastReceiver`. Step #3: Arrange to start that service when appropriate. However, unless you can justify to the user keeping a service running all of the time, using the polling approach that I mention in a comment on [the answer that Hemant linked to](https://stackoverflow.com/a/45996525/5110595) is a more sustainable solution. – CommonsWare Mar 19 '18 at 12:15
  • @CommonsWare, in case I am going to use this receiver when my app is running, how can I register `ACTION_PACKAGE_ADDED` programmatically? There is no need to constantly listen to this event. – Nolesh Mar 19 '18 at 12:26
  • Call `registerReceiver()` on some `Context`. I don't know what "when my app is running" means, exactly. If you mean "when my process happens to be running for other reasons", you could create a custom `Application` subclass, have it call `registerReceiver()` on itself in its `onCreate()`, and register that `Application` via `android:name` on the `` element in the manifest. – CommonsWare Mar 19 '18 at 12:27
  • @CommonsWare, like this: `Receiver r = new Receiver(); //extended from BroadcastReceiver class IntentFilter i = new IntentFilter("android.intent.action.PACKAGE_ADDED"); i.addDataScheme("package"); ctx.registerReceiver(r, i);` ? – Nolesh Mar 19 '18 at 12:35
  • That looks good, though you will want to hold onto your `Receiver` instance, so you can call `unregisterReceiver()` at the appropriate point. Also, I'd use `Intent.ACTION_PACKAGE_ADDED`, rather than hard-coding the action string. – CommonsWare Mar 19 '18 at 12:39
  • @CommonsWare, ok. Thank you. I'll try it later. Unfortunately, I don't have Oreo device to check it. But I can check it on Lolipop by removing implicit receivers from `manifest` – Nolesh Mar 19 '18 at 12:42

1 Answers1

3

I have decided to create a simple service for listening to PACKAGE_ADDED event.

public class MyService extends Service {
  private BroadcastReceiver receiver;

  public MyService() { }

  @Override
  public void onCreate() {
    IntentFilter intentFilter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
    intentFilter.addDataScheme("package");
    receiver = new Receiver();
    registerReceiver(receiver, intentFilter);
  }

  //ensure that we unregister the receiver once it's done.
  @Override
  public void onDestroy() {
    unregisterReceiver(receiver);
  }

  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

}

Also, I needed to declare my service in manifest file:

<service
    android:name="com.nolesh.myapp.MyService"
    android:enabled="true">
</service>
Nolesh
  • 6,848
  • 12
  • 75
  • 112
  • 1
    Note that this will only work when your application is in the foreground. > While an app is idle, there are limits to its use of background services. > When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods. Reference: https://developer.android.com/about/versions/oreo/background – avelyne Dec 19 '18 at 09:18
  • @avelyne, what if I make my service immortal? If it is going to be destroyed, it recreates itself again. – Nolesh Dec 19 '18 at 13:17
  • 1
    I am not sure exactly how you are achieving the logic of re-creating the service when it is destroyed. But if that restart logic is something that is not considered as something "foreground", then your app will crash with some exception that states that you are not allowed to start a service from the background. To check if a component is considered as "foreground", refer to: https://developer.android.com/about/versions/oreo/background#services – avelyne Dec 20 '18 at 14:56
  • @avelyne I have the opposite problem. The `ForegroundService` prevents standby and drains the battery. As apps will not get installed in standby, the service should allow it to happen and return being active when the phone comes back from standby. – Giszmo Jun 21 '20 at 20:21