Как приложение может обнаружить, что оно будет удалено? [дубликат]


этот вопрос уже есть ответ здесь:

  • Можно ли обнаружить удаление приложения для Android? 7 ответов
  • Выполните задачу по удалению в android [дубликат] 4 ответы

все мы знаем, что обычно (на практике любое) антивирусное приложение перед удалением используется для запуска простого диалога, например: "вы собираетесь удалить приложение, вы уверены?"- "да/нет".

Да, я знаю, что могу перехватить намерение удаления пакета с помощью intent-filter, например:

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

но проблема в простом факте, что это перехватывает любой удалить запросы и, кроме того, это вызовет диалог выбора между моим приложением и установщиком акций. Так что если пользователь выберет stock installer - я не смогу этого сделать что угодно.

моя цель состоит не в том, чтобы предотвратить удаление пользователем моего приложения, а просто откат изменений, внесенных моим приложением.

изучая эти антивирусные приложения, я вижу, что такая операция возможна, поэтому, пожалуйста, помогите мне и объясните, как это возможно?

обновление

Так как есть некоторые ребята, которые не верят, что это реально - я бы сослался на Avast Mobile Security:

Анти-Кражи защищает себя от удаления, маскируя ее компонентов с различными самосохранения техники.

другой пример: Kaspersky Internet Security для Android -вот специальная процедура для удаления его, который требует ввода секретного кода.

в любом случае это означает, что есть способ перехватить процедуру удаления, чтобы либо предотвратить удаление, либо выполнить некоторую завершающую работу.

4 55

4 ответа:

ОК. Я много исследовал эту проблему с 2 дней и, наконец, нашел "дикий способ" решить ее без укоренения устройства:)

во-первых, вот основные моменты для достижения решения:

1. когда пользователь переходит к Настройки -> Управление приложениями -> выбор приложения мы получаем трансляцию android.намерение.действие.QUERY_PACKAGE_RESTART С именем пакета приложения как дополнительный.

2. после этого, когда мы нажимаем на удалить кнопка (с установщиком пакета), она открывает действие с именем - com.андроид.packageinstaller.UninstallerActivity

поток управления будет выглядеть так:

в настройках приложения пользователь нажимает на кнопку ---> Удалить мы вам контроль, чтобы показать диалог запуска / иной деятельности / и т. д. ---> Мы заканчиваем наш предварительный-удаление задача - - - > пользователь возвращается обратно на экран подтверждения удаления - - - > пользователь подтверждает и удаляет приложение

Используется Способ:

мы реализуем BroadcastReceiver в нашем приложении для прослушивания действия"android.намерение.действие.QUERY_PACKAGE_RESTART " и соответствует нашему имени пакета внутри метода onReceive (). Если трансляция была получена для выбора желаемого пакета приложений, то мы будем инициируйте фоновый поток, который будет продолжать отслеживать выполняемые действия переднего плана с помощью ActivityManager.

как только мы находим деятельность переднего плана, чтобы быть" com.андроид.packageinstaller.UninstallerActivity", это будет подтвердить, что пользователь хочет удалить наше приложение. На этом этапе мы выполним необходимые задачи (либо отобразим диалог, либо запустим другое действие, перекрывающее окно удаления и т. д..), которые должны быть выполнены перед деинсталляция. После выполнения нашей задачи, мы позволим пользователю продолжить с подтверждением процесса удаления.

Реализация / Исходный Код:

в манифесте.xml

добавить разрешения:

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

и широковещательного приемника:

<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 (класс радиовещательного приемника)

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 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();
    }
}

Известные Ограничения:

когда пользователь нажимает на удалить кнопка в разделе Управление настройками приложений, мы будем выполнять наши задачи перед удалением, а затем promt пользователя в окно подтверждения, где пользователь может либо подтвердить, чтобы удалить или может отмена операции.

описанный выше подход на данный момент не охватывает случай, если пользователь нажимает на отмена после того, как мы выполнили нашу задачу. Но это можно было легко решить с некоторыми дополнениями.

например: мы можем реализовать логику, чтобы вернуть изменения, которые мы сделали, если трансляция"android.намерение.действие.PACKAGE_REMOVED " не был получен в конце концов.

Я надеюсь, что этот подход будет полезен для вас :) так как это единственный способ, на мой взгляд, мы можем решить вашу проблему без укоренения устройства!

[обновление 1]: Предложенный подход, чтобы проверить, если Задача удаления была отменено:

забавно, что раньше у меня была совершенно другая и гораздо более сложная идея(включая трансляции, ActivityManager и т. д.. так далее..), но при написании его здесь просто еще одна идея поразила меня, которая сравнительно очень проста :)

когда пользователь нажимает кнопку "Удалить" в разделе "Управление настройками приложений" и после выполнения задач перед удалением, вы просто устанавливаете в своем приложении некоторые SharedPreference, которые вы выполнили задачи перед удалением и готовы к удалению. После этого вам не нужно ни о чем заботиться.

если пользователь продолжает удалять -> его хорошо и хорошо, как вы уже выполнили необходимые задачи.

в то время как если пользователь, наконец, нажимает на отмена кнопка и уходит - > не беспокойтесь. Пока пользователь не пойдет и не запустит ваше приложение снова. Теперь внутри "onStart ()" / "onResume ()" основной деятельности вашего приложения, вы можете проверить значение SharedPreference, и если оно было установлено для удаления, это будет означать, что пользователь окончательно не приступил к удалению. И теперь вы можете отменить изменения, внесенные ранее(отменяя выполненные задачи перед удалением), чтобы убедиться, что ваше приложение работает отлично!

другой вариант обнаружения удаления приложения - использование собственного кода.

вы должны контролировать для вашего каталога с помощью inotify рамки в раздвоенном процессе.

когда он удален, вы можете запустить некоторую системную команду, например. начинается Intent

PoC такого решения: https://github.com/pelotasplus/ActionAfterUninstall/blob/master/app/src/main/jni/hello-jni.c

это просто невозможно в Android

ваше приложение не может знать, что оно удаляется (без изменения ядра). Все файлы, созданные в data/data / your.приложение.пакет удаляется автоматически при установке.

другой подход может заключаться в том, чтобы иметь другое приложение, которое проверяет, установлено ли это приложение или нет. Если нет, то он может сделать работу по очистке.

обновление

в ACTION_PACKAGE_REMOVED намерение будет отправлено всем получателям, кроме вашего собственного. Это подтверждается здесь.

обновление 2

просто еще одна мысль.

когда я искал это, я обнаружил, что это можно сделать, отслеживая logcat для вашего приложения здесь является образцом logcat monitor

хорошо, что для мониторинга logcat для того же приложения нам не нужно иметь корневой устройство

и когда мы читаем каждую запись в logcat, мы можем искать следующую строку

Received broadcast Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.package.name flg=0x8000010 (has extras) }

поскольку это событие получено, мы знаем, что наше приложение теперь будет не установлено

не пробовал, хотя

снова мониторинг logcat не допускается с Android Jellybean

для того, чтобы ваше приложение сохранялось, вам нужно иметь корневое устройство и иметь возможность установить его в системный раздел. Как только он там появится, вы можете удалить обновления, так как они сохраняются вместе с несистемными приложениями, но это не так просто, чтобы удалить его из системы.

Я знаю, что некоторые из них также сохранят немного данных в системном разделе на случай, если устройства будут сброшены с завода, но есть также способы заставить менеджера пакетов оставить позади ваши сохраненные данные в том случае, если они просто удалены.

другой вариант-зарегистрировать его в качестве администратора устройства. Как только вы это сделаете, они не смогут удалить его, если они вручную не удалят его статус администратора.

enter image description here

<item name="android.permission.ACCESS_SUPERUSER" />

здесь похоже, что они используют root, а также другие методы. За исключением создания какой-то сумасшедшей сложной службы, которая, похоже, у них может быть, нет законного способа сделать это другой способ.

использование root-это почти стандартная практика для таких приложений AV/security, без нее у них нет реальной власти над любыми другими приложениями, поэтому они очень ограничены. Я думаю, что разрешение суперпользователя не отображается, если вы его не установили, поэтому многие люди все еще не знают, что это вариант.

<perms>
<item name="android.permission.READ_EXTERNAL_STORAGE" />
<item name="android.permission.GET_TASKS" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" />
<item name="android.permission.WRITE_CALL_LOG" />
<item name="com.avast.android.generic.CENTRAL_SERVICE_PERMISSION" />
<item name="android.permission.WRITE_SMS" />
<item name="android.permission.ACCESS_WIFI_STATE" />
<item name="android.permission.RECEIVE_SMS" />
<item name="android.permission.GET_ACCOUNTS" />
<item name="android.permission.READ_CONTACTS" />
<item name="android.permission.CALL_PHONE" />
<item name="android.permission.WRITE_CONTACTS" />
<item name="android.permission.READ_PHONE_STATE" />
<item name="android.permission.READ_SMS" />
<item name="android.permission.RECEIVE_BOOT_COMPLETED" />
<item name="android.permission.ACCESS_SUPERUSER" />
<item name="com.avast.android.mobilesecurity.permission.C2D_MESSAGE" />
<item name="android.permission.GET_PACKAGE_SIZE" />
<item name="android.permission.WAKE_LOCK" />
<item name="android.permission.ACCESS_NETWORK_STATE" />
<item name="android.permission.USE_CREDENTIALS" />
<item name="android.permission.SEND_SMS" />
<item name="android.permission.RECEIVE_MMS" />
<item name="com.google.android.c2dm.permission.RECEIVE" />
<item name="android.permission.KILL_BACKGROUND_PROCESSES" />
<item name="com.android.vending.BILLING" />
<item name="android.permission.WRITE_SETTINGS" />
<item name="android.permission.INTERNET" />
<item name="android.permission.VIBRATE" />
<item name="android.permission.READ_CALL_LOG" />
<item name="com.avast.android.generic.COMM_PERMISSION" />
<item name="com.dolphin.browser.permission.ACCESS_PROVIDER" />
<item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
</perms>