Ask for password before uninstalling application

2019-01-06 21:42发布

First of all, I have researched a lot about my issue, but I could not find a proper solution so I am posting my query here. Hope to get a better solution to the issue:

I have a requirement where I need to ask for password to the user before user deletes my app from settings or from any other application like MyAppSharer. I have found one solution where I can successfully be able to call my activity when user clicks on Uninstall button. I have applied trick here, and calling service. In service, I run timer which runs every 1 second and in that one second, it checks for top most activity of running task. This is running perfectly as per expected.

Now, my issue is, this activity apppears on each of application user tries to uninstall. I need that the activity which I call, should only appear for my application when user tries to uninstall my application.

Here is my code:

public static final String PACKAGE_INSTALLER = "com.android.packageinstaller";
public static final String PACKAGE_INSTALLER_UNINSTALL_ACTIVITY = "com.android.packageinstaller.UninstallerActivity";


alarmTimer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);;
            ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;

            final String packageName = topActivity.getPackageName();
            String className = topActivity.getClassName();

            Log.v(TAG, "packageName:" + packageName);
            Log.v(TAG, "className:" + className);

            if (PACKAGE_INSTALLER.equals(packageName)
                && PACKAGE_INSTALLER_UNINSTALL_ACTIVITY.equals(className)) {

                //Here I need to apply one condition where package name received to be matched with my package name. But I am not sure how to fetch package name of selected application for uninstalling 
                //To Cancel Existing UninstallerActivity and redirect user to home.
                Intent homeIntent = new Intent();
                homeIntent.setAction(Intent.ACTION_MAIN);
                homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                homeIntent.addCategory(Intent.CATEGORY_HOME);
                startActivity(homeIntent);

                //To open my activity
                    Intent loginActivity = new Intent(UninstallService.this, Act_Login.class);
                    loginActivity.putExtra(Constants.KEY_IS_FROM_SERVICE, true);
                    loginActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(loginActivity); 

            }
        }
    }, 0, 1000);

4条回答
小情绪 Triste *
2楼-- · 2019-01-06 22:08

If you have root permissions make your app system (remove your apk-file from /data to /system directories). Then reboot device. After reboot your app is not available to delete by user (not superuser).

查看更多
ら.Afraid
3楼-- · 2019-01-06 22:12

The only way i see, is to provide your own uninstaller as part of your app (= an activity that lists all apps and allows to uninstall them). Your service could then check if your app was the one that started the packageinstaller and if not redirect the user.

It is not possible (at least on the Android 4.4 I tested with) to grab the uninstaller activity data without root or being a system app. This is because the uninstaller is not called as an independent task, but as an activity on the stack of the starting task (which is the Settings app when uninstalling from settings, etc). You can only see the Task details of the calling task.

However there might be some really dirty possibility left, that i didn't test to the end: You could register the hidden interface IThumbnailReceiver [1] with the hidden three argument version of ActivityManager.getRunningTasks [2]. It seems like only the GET_TASKS permission is needed to grab a thumbnail (see [3]). It should be possible to find out which app is going to be removed from the app thumbnail... - But as this solution uses hidden APIs, there is no guarantee that it will work with older/newer/vendored Android versions.

  1. https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/IThumbnailReceiver.aidl
  2. https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/ActivityManager.java#L766
  3. https://github.com/omnirom/android_frameworks_base/blob/android-4.4/services/java/com/android/server/am/ActivityManagerService.java#L6725
查看更多
ら.Afraid
4楼-- · 2019-01-06 22:13

you should try something like the following :

1st - declare your broadcast recevier in the Manifest file , that will listen to QUERY_PACKAGE_RESTART :

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

2nd - your UnunstallIntentReceiver java class like the following :

public class UninstallReceiver 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("application_package")){
                   // start your activity here and ask the user for the password 
                }
            }
        }
    }

    }

and please give me some feedback

Hope That Helps.

查看更多
Viruses.
5楼-- · 2019-01-06 22:13

If this is a corporate requirement (if you want to block a regular user from uninstalling your app, no chance, thanks Google for protecting us from bad devs), you should create a device administrator application. This way, although the user still can delete the app, it's one extra step if you want to prevent accidental erasing.

Before deleting your app, if it's enabled as device admin, the user must first disable the app as administrator, and the app receives this broadcast.

In your XML, put

<activity android:name=".app.DeviceAdminSample"
            android:label="@string/activity_sample_device_admin">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.SAMPLE_CODE" />
    </intent-filter>
</activity>
<receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver"
        android:label="@string/sample_device_admin"
        android:description="@string/sample_device_admin_description"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
    <meta-data android:name="android.app.device_admin"
            android:resource="@xml/device_admin_sample" />
    <intent-filter>
        <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    </intent-filter>
</receiver>

In the receiver, you have at least two methods worth noticing:

@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
    …
}

@Override
public void onDisabled(Context context, Intent intent) {
    …
}

This way you know the user is potentially going to erase your app.

Complete guide for device administration is at https://developer.android.com/guide/topics/admin/device-admin.html

查看更多
登录 后发表回答