Can't get receiver when the app uninstall

2019-01-12 07:40发布

问题:

I refer this information.

I write the same program, but I can't get any log info when I click uninstall button .

I attach my code below. Have anyone know what's problem in this code?

I want to do something when use click uninstall button. Maybe like turn on browser, etc.

Have any one can give me a hand?

The problem has confused me for a long time.

My AndroidManifest:

...

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

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
 <receiver android:name=".UninstallIntentReceiver" >
        <intent-filter>
           <action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
           <action  android:name = "android.intent.action.PACKAGE_REMOVED"  />
           <action  android:name = "android.intent.action.PACKAGE_ADDED"  />
           <data android:scheme="package"></data>
        </intent-filter>
    </receiver>
</application>

...

my BroadcastReceiver code below:

public class UninstallIntentReceiver extends BroadcastReceiver{

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

    String [] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
    if(packageNames!=null){
        for(String packageName: packageNames){
            if(packageName!=null && packageName.equals("yu.idv.uninstalldetected")){
                Log.i("info", "00000000"); 
               new ListenActivities(context).start();
               Log.i("info", "11111111");

            }
        }
    }
  }

}

class ListenActivities extends Thread{
boolean exit = false;
ActivityManager am = null;
Context context = null;

public ListenActivities(Context con){
    context = con;
    am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}

public void run(){

    Looper.prepare();

    while(!exit){

         List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY);

         String activityName = taskInfo.get(0).topActivity.getClassName();


         Log.i("info", "======CURRENT Activity =======::"
                 + activityName);

         if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
             exit = true;
             Log.i("info", "2222222222");                
            Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now",            Toast.LENGTH_SHORT).show();
        } else if(activityName.equals("com.android.settings.ManageApplications")) {
            exit=true;
             Log.i("info", "33333333333");
        }
    }
    Looper.loop();
}

回答1:

The reason that your BroadcastReceiver is not called is that your application is still in "stopped state". Your application doesn't have any Activity components. This means that after the application is installed there is no way for the user to start it. Applications that have never been started by the user stay in the "stopped state". Applications in the "stopped state" will not receive broadcast Intents.

See the section on "Launch controls on stopped applications" in http://developer.android.com/about/versions/android-3.1.html


EDIT: Add more details regarding Intent.ACTION_QUERY_PACKAGE_RESTART in Android 4.x

It seems that this behaviour has changed since Android 2.3 (I'm not sure about Android 3.x). In Android 4.0 and above, the code in InstalledAppDetails (part of the Settings application) looks like this:

 private void checkForceStop() {
     if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
         // User can't force stop device admin.
         updateForceStopButton(false);
     } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
         // If the app isn't explicitly stopped, then always show the
         // force stop button.
         updateForceStopButton(true);
     } else {
         Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
                 Uri.fromParts("package", mAppEntry.info.packageName, null));
         intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
         intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
         getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
                 Activity.RESULT_CANCELED, null, null);
     }
 }

So, if the application being shown is a device admin, the "force stop" button will be disabled. If the application being shown is not stopped, then the "force stop" button will be enabled. Otherwise, Intent.ACTION_QUERY_PACKAGE_RESTART will be broadcasted.

This means that the Intent will only be broadcasted for non-device-admin applications that are already stopped.

I tested this on a 4.0 device with your code. If you install your application, then you go to Settings->Apps and choose another application (not yours) that has been "force stopped", your onReceive() is called with Intent.ACTION_QUERY_PACKAGE_RESTART.

I realized this probably isn't much help, but it at least explains the behaviour that you are seeing.

Sorry it took so long to solve this, and thanks for the challenge :-)



回答2:

Generally when you are uninstalling the application, all the resources are removed from the device. so you can not trigger any action at the time of un-installing