Receiving package install and uninstall events

AndroidBroadcastreceiver

Android Problem Overview


I am trying to detect when a new App is being installed but only if my app is running. I managed to detect the installation of the app by making a BroadcastReceiver and activating it inside the AndroidManifest file but this will detect even if my app is closed. So that is why I need to manually activate and deactivate the broadcastreveiver. To do this I have this code:

br = new BroadcastReceiver() {
		
	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		Log.i("Enter", "Enters here");
		Toast.makeText(context, "App Installed!!!!.", Toast.LENGTH_LONG).show();
	}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_INSTALL);
registerReceiver(br, intentFilter);

This should make a toast when a new app is installed. But sadly it does not. It does not enter in the onReceive method. Any help is appreciated.

Android Solutions


Solution 1 - Android

I tried to register the BroadcastReceiver in either manifest file or java code. But both of these two methods failed to trigger the onReceive() method. After googling this problem, I found a solution for both methods from another Thread in SO: https://stackoverflow.com/questions/5499025/android-notification-app

In the manifest file (this approach no longer applies since API 26 (Android 8), it was causing performance issues on earlier Android versions):

<receiver android:name=".YourReceiver">
	<intent-filter>
		<action android:name="android.intent.action.PACKAGE_INSTALL" />
		<action android:name="android.intent.action.PACKAGE_ADDED" />
		<data android:scheme="package"/>
	</intent-filter>
</receiver>

In java code:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_INSTALL);
intentFilter.addDataScheme("package");
registerReceiver(br, intentFilter);

This should work for you.

Solution 2 - Android

Other answers point out listening for ACTION_PACKAGE_ADDED and ACTION_PACKAGE_REPLACED broadcasts. That is fine for Android 7.1 and lower. On Android 8.0+, you cannot register for those broadcasts in the manifest.

Instead, you need to call getChangedPackages() on PackageManager periodically, such as via a periodic JobScheduler job. This will not give you real-time results, but real-time results are no longer an option on Android 8.0+.

Solution 3 - Android

Just to add to Huang's answer above, here is how to get the package name of the newly installed application:

public class YourReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String packageName = intent.getData().getEncodedSchemeSpecificPart();
    }
}

Solution 4 - Android

This code is for REMOVED_APPLICATION .

With below code, U did not need to Use manifest.Just in ur Java Class Write This code .

 BroadcastReceiver  uninstallApplication = new BroadcastReceiver() {

      @Override
      public void onReceive(Context context, Intent intent) {

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
          String packageName = Objects.requireNonNull(intent.getData()).getEncodedSchemeSpecificPart();

       Toast.makeText(context, "USER UNINSTALL : " + packageName, Toast.LENGTH_SHORT).show();

     


        }
      }
    };
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    intentFilter.addDataScheme("package");
    registerReceiver(uninstallApplication, intentFilter);

Solution 5 - Android

This solution does not use any kind of Receiver or Intent just Kotlin and coroutines, so it is not limited by any android version.

  1. I created a method to return if my app is installed or not using PackageManager.
private fun isAppInstalled(): Boolean {
        return try {
            val appPackageInfo = packageManager.getPackageInfo(packageName, 0)
            true
        } catch (e: PackageManager.NameNotFoundException) {
            false
        }
    }
  1. Then I created another method that returns a Deferred with a Boolean as value to finish only when my app is installed or when it achieves the timeout limit.
override suspend fun returnWhenAppIsInstalledAsync(): Deferred<Boolean> = ioScope.async {
        while (isActive) {
            var delayCount = 0
            if(isAppInstalled()) {
                return@async true
            } else {
                delay(1000)
                delayCount++
                if(delayCount == 30) return@async false
            }
        }
        return@async false
    }
  1. So I start to await for it to returns after the session commit
...
session.commit(intentSender)
val wasAppInstalled = viewModel.returnWhenAppIsInstalledAsync().await()
if(wasAppInstalled) {
  // Here you can handle any logic
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPetre PopescuView Question on Stackoverflow
Solution 1 - AndroidHuangView Answer on Stackoverflow
Solution 2 - AndroidCommonsWareView Answer on Stackoverflow
Solution 3 - AndroidTHANN PhearumView Answer on Stackoverflow
Solution 4 - AndroidSana EbadiView Answer on Stackoverflow
Solution 5 - AndroidmanoellribeiroView Answer on Stackoverflow