How can an app detect that it's going to be uninstalled?

Barmaley

All we know that usual (in practice any) antivirus application before uninstall used to fire simple dialog like: "You're going to uninstall app, are you sure?" - "yes/no".

Yes, I know that I can intercept package delete intent using intent-filter like:

<activity
    android:name=".UninstallIntentActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <action android:name="android.intent.action.DELETE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="package"  />
    </intent-filter>
</activity>

But problem is in simple fact that this intercepts any delete requests and moreover this will fire chooser dialog between my app and stock installer. So if user will select stock installer - I won't be able to do anything.

My goal is not to prevent user from uninstalling of my app, but just rollback changes made by my app.

Learning from those antivirus apps I see that this kind of operation is possible, so please help me and explain how it is possible?

Update

Since there are some guys who doesn't believe that it's real - I would refer to Avast Mobile Security:

Anti-Theft protects itself from uninstall by disguising its components with various self-preservation techniques.

Another example: Kaspersky Internet Security for Android - here's special procedure for uninstalling it, which requires entering of secret code.

Anyway it means that there's way to intercept uninstallation procedure in order to either prevent uninstall or do some finalizing job.

AnniJais

Okay. I have been investigating a lot on this problem since 2 days and finally found a "wild way" to solve it without rooting the device :)

First, here are the highlights to achieve the solution:

1. Whenever user goes to Settings -> Manage Apps -> Selects a particular application we receive a broadcast android.intent.action.QUERY_PACKAGE_RESTART with name of the application's package as extras.

2. After that when we click on the Uninstall button (with package installer), it opens an activity named - com.android.packageinstaller.UninstallerActivity

Control flow will be like:

Under App Settings the User Clicks on Uninstall button ---> We get control to show a dialogue / start another activity / etc ---> We finish our Pre-Uninstallation task ---> User is Returned back to Uninstallation confirmation screen ---> User confirms and uninstalls the app

Used Method:

We will implement a BroadcastReceiver in our application for listening the action "android.intent.action.QUERY_PACKAGE_RESTART" and match our package name inside onReceive() method. If the broadcast was received for selection of our desired application package, then we'll initiate a background thread that will keep monitoring the foreground running activities using the ActivityManager.

Once we find the foreground activity to be "com.android.packageinstaller.UninstallerActivity", it'll be confirm that user wants to uninstall our application. At this point we'll perform the desired tasks (either display a dialogue, or start another activity overlapping the uninstallation window, etc..) that are to be performed before uninstallation. After performing our task, we'll allow the user to continue with confirming the uninstallation process.

Implementation / Source Code:

In manifest.xml

add permission:

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

and broadcast receiver:

<receiver android:name=".UninstallIntentReceiver">
      <intent-filter android:priority="0">
            <action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
            <data android:scheme="package" />
      </intent-filter>
 </receiver>

UninstallIntentReceiver.java (broadcast receiver class)

public class UninstallIntentReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        // fetching package names from extras
        String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES"); 

        if(packageNames!=null){
            for(String packageName: packageNames){
                if(packageName!=null && packageName.equals("YOUR_APPLICATION_PACKAGE_NAME")){
                    // User has selected our application under the Manage Apps settings
                    // now initiating background thread to watch for activity
                    new ListenActivities(context).start();

                }
            }
        }
    }

}

ListenActivities class - for monitoring the foreground activities

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){

             // get the info from the currently running task
             List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY); 

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


             Log.d("topActivity", "CURRENT Activity ::"
                     + activityName);

             if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
                // User has clicked on the Uninstall button under the Manage Apps settings

                 //do whatever pre-uninstallation task you want to perform here
                 // show dialogue or start another activity or database operations etc..etc..

                // context.startActivity(new Intent(context, MyPreUninstallationMsgActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                 exit = true;
                 Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now", Toast.LENGTH_SHORT).show();
            } else if(activityName.equals("com.android.settings.ManageApplications")) {
                // back button was pressed and the user has been taken back to Manage Applications window
                          // we should close the activity monitoring now
                exit=true;
            }
        }
        Looper.loop();
    }
}

Known Limitations:

When the user clicks on the Uninstall button under Manage Apps settings, we'll perform our pre-uninstallation tasks and then promt the user to the Confirmation window where user can either confirm to uninstall or can Cancel the operation.

The approach described above is as of now not covering the case if user clicks on Cancel button after we have performed our task. But this could be tackled easily with some ammendments.

E.g.: We can implement a logic to revert the changes we made if the broadcast "android.intent.action.PACKAGE_REMOVED" was not received in the end.

I hope this approach will be helpful to you :) As this is the only way in my opinion we can solve your problem without rooting the device!

[Update 1]: Suggested Approach to check if the Uninstallation task was Canceled:

Its kind of funny that I had entirely different and much complex idea earlier(involving broadcasts, ActivityManager, etc.. etc..), but while writing it here just another idea struck into my mind which is comparatively very simple :)

When the User clicks on Uninstall button under Manage Apps settings and after you have performed your pre-uninstallation tasks, you just set some SharedPreference in your app that you have performed the pre-uninstall tasks and are ready for uninstallation. After this you need not to care about anything.

If the user continues to uninstall -> its well and good as you have already performed required tasks.

While if user finally clicks on Cancel button and goes away -> don't bother. Until the user goes and run your application again. Now inside "onStart()" / "onResume()" of your application's main activity, you can check the SharedPreference's value and if it was set for uninstallation, that will mean that user didn't finally proceeded with the uninstallation. And now you could revert the changes made earlier(reversing the pre-uninstall tasks performed) to ensure that your application runs perfectly!

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

How to detect system timer going off in iOS

分類Dev

How can a JavaScript app detect if a Leap Motion device is connected

分類Dev

Can I keep stored data for a Greasemonkey script even when it's uninstalled?

分類Dev

How to handle the deletion of my registraion_id in my online database server if the gcm enabled android app is uninstalled without internet connection

分類Dev

How can I reinstall Windows 10's calculator app?

分類Dev

Swift, macos - Can I detect or make other app to be in the foreground?

分類Dev

How HTTPs proxies can detect HTTPs packets?

分類Dev

How can I detect a hidden Desktop?

分類Dev

How can I detect embeds in a message?

分類Dev

How many (classes of) objects can YOLO detect?

分類Dev

How can we detect notification cancel?

分類Dev

How to know if application data is cleared or application is uninstalled?

分類Dev

What's going on in this for loop?

分類Dev

How to detect whether it's the same StatusBarNotification

分類Dev

Are iPhone's apps notifications going to be triggered on the Apple Watch by default, without even creating an actual Watch app?

分類Dev

Can't understand what's going on with EventEmitter using webpack and es6 modules

分類Dev

Gentoo and Systemd: Can openrc be uninstalled without breaking other packages?

分類Dev

How to detect programmatically if "Android App" is running in chrome book or in Android phone

分類Dev

Swift (4.1) how to detect if me app was open from external source

分類Dev

How to detect installed Chrome version from my Android App?

分類Dev

How to detect installed Chrome version from my Android App?

分類Dev

How can I detect how many capture groups are in a Perl Regexp?

分類Dev

How can I display the user's live wallpaper as background in my app?

分類Dev

How can I add an MDDataTable to a Screen in a class that's not the main app class?

分類Dev

How can we programmatically detect which iOS version is device running on?

分類Dev

How can I detect macOS command keys in JavaScript

分類Dev

How can I make Github desktop detect changes in STS?

分類Dev

How can I detect a tap event in a child class of UIView?

分類Dev

How can I detect if a label has a specific class?

Related 関連記事

  1. 1

    How to detect system timer going off in iOS

  2. 2

    How can a JavaScript app detect if a Leap Motion device is connected

  3. 3

    Can I keep stored data for a Greasemonkey script even when it's uninstalled?

  4. 4

    How to handle the deletion of my registraion_id in my online database server if the gcm enabled android app is uninstalled without internet connection

  5. 5

    How can I reinstall Windows 10's calculator app?

  6. 6

    Swift, macos - Can I detect or make other app to be in the foreground?

  7. 7

    How HTTPs proxies can detect HTTPs packets?

  8. 8

    How can I detect a hidden Desktop?

  9. 9

    How can I detect embeds in a message?

  10. 10

    How many (classes of) objects can YOLO detect?

  11. 11

    How can we detect notification cancel?

  12. 12

    How to know if application data is cleared or application is uninstalled?

  13. 13

    What's going on in this for loop?

  14. 14

    How to detect whether it's the same StatusBarNotification

  15. 15

    Are iPhone's apps notifications going to be triggered on the Apple Watch by default, without even creating an actual Watch app?

  16. 16

    Can't understand what's going on with EventEmitter using webpack and es6 modules

  17. 17

    Gentoo and Systemd: Can openrc be uninstalled without breaking other packages?

  18. 18

    How to detect programmatically if "Android App" is running in chrome book or in Android phone

  19. 19

    Swift (4.1) how to detect if me app was open from external source

  20. 20

    How to detect installed Chrome version from my Android App?

  21. 21

    How to detect installed Chrome version from my Android App?

  22. 22

    How can I detect how many capture groups are in a Perl Regexp?

  23. 23

    How can I display the user's live wallpaper as background in my app?

  24. 24

    How can I add an MDDataTable to a Screen in a class that's not the main app class?

  25. 25

    How can we programmatically detect which iOS version is device running on?

  26. 26

    How can I detect macOS command keys in JavaScript

  27. 27

    How can I make Github desktop detect changes in STS?

  28. 28

    How can I detect a tap event in a child class of UIView?

  29. 29

    How can I detect if a label has a specific class?

ホットタグ

アーカイブ