Как приложение может обнаружить, что оно будет удалено?
Все, что мы знаем, что обычное (на практике любое) антивирусное приложение перед удалением использовало для запуска простого диалогового windows, например: «Вы собираетесь удалить приложение, вы уверены?» – “да нет”.
Да, я знаю, что я могу перехватить намерение удалить пакет с помощью фильтра-замысла, например:
Но проблема заключается в простом факте, что это перехватывает любые запросы на удаление, и, кроме того, это сработает диалог выбора между моим приложением и установщиком запаса. Поэтому, если пользователь выберет установщик запаса – я ничего не смогу сделать.
- Выполните задачу по удалению в android
- Как предотвратить удаление приложения?
- Как удалить пакет из Laravel с помощью композитора?
- Как показать активность до того, как мое приложение будет удалено (Android)
- Как исправить ошибки несоответствия версии pg_dump?
Моя цель состоит не в том, чтобы запретить пользователю удалять мое приложение, а просто отменить изменения, сделанные моим приложением.
Изучая эти антивирусные приложения, я вижу, что такая операция возможна, поэтому, пожалуйста, помогите мне и объясните, как это возможно?
Обновить
Поскольку есть некоторые ребята, которые не считают, что это реально – я бы назвал Avast Mobile Security :
Anti-Theft защищает себя от удаления путем маскировки его компонентов различными методами самосохранения.
Другой пример: Kaspersky Internet Security для Android – вот специальная процедура для его удаления , которая требует ввода секретного кода.
В любом случае это означает, что есть способ перехватить процедуру удаления, чтобы либо предотвратить удаление, либо выполнить некоторую работу по завершению.
- Почему MSI требует, чтобы исходный файл .msi продолжал деинсталляцию?
- Получить событие удаления приложения в android
- Принудительное удаление Visual Studio 2015
- Полностью удалить PostgreSQL 9.0.4 от Mac OSX Lion?
- установить / удалить APK программно (PackageManager vs Intents)
- Неявное намерение удалить приложение?
- Что противоположно «make install», то есть как вы удаляете библиотеку в Linux?
Хорошо. Я много разбираюсь в этой проблеме с 2-х дней и, наконец, нашел «дикий способ» решить ее, не укореняя устройство 🙂
Во-первых, вот основные моменты для достижения решения:
1. Когда пользователь переходит в Настройки -> Управление приложениями -> Выбирает конкретное приложение, мы получаем широковещательный android.intent.action.QUERY_PACKAGE_RESTART с именем пакета приложения в качестве дополнительных функций.
2. После этого, когда мы нажимаем кнопку « Удалить» (с установщиком пакетов), она открывает действие с именем – com.android.packageinstaller.UninstallerActivity
Управляющий stream будет выглядеть следующим образом:
В разделе «Настройки приложения» кнопка «Пользователь нажимает кнопку« Удалить »—> Мы получаем контроль, чтобы показать диалог / запустить другое мероприятие / etc —> Закончить задачу« Предварительная деинсталляция »—> Пользователь возвращается на экран подтверждения удаления – -> Пользователь подтверждает и удаляет приложение
Используемый метод:
Мы будем использовать BroadcastReceiver в нашем приложении для прослушивания действия « android.intent.action.QUERY_PACKAGE_RESTART » и соответствия имени нашего пакета внутри метода onReceive (). Если трансляция была получена для выбора нашего желаемого пакета приложений, мы начнем фоновый stream, который будет отслеживать действия, выполняемые переднего плана, используя ActivityManager.
Как только мы увидим, что переднего плана будет « com.android.packageinstaller.UninstallerActivity », он будет подтверждать, что пользователь хочет удалить наше приложение. На этом этапе мы выполним требуемые задачи (либо отобразим диалог, либо запустим другое действие, перекрывающее окно удаления и т. Д.), Которые должны быть выполнены перед деинсталляцией. После выполнения нашей задачи мы разрешим пользователю продолжить подтверждение процесса удаления.
Реализация / Исходный код:
В manifest.xml
добавить разрешение:
и широковещательный приемник:
UninstallIntentReceiver.java (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 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(); } }
в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(); } }
Известные ограничения:
Когда пользователь нажимает кнопку « Удалить» в настройках «Управление приложениями», мы выполним наши задачи перед удалением, а затем предложим пользователю окно подтверждения, в котором пользователь может либо подтвердить удаление, либо может отменить операцию.
Описанный выше подход сейчас не распространяется на случай, если пользователь нажимает кнопку « Отмена» после выполнения нашей задачи. Но с этим можно легко справиться с некоторыми изменениями.
Например: мы можем реализовать логику, чтобы вернуть изменения, которые мы сделали, если в конце не была получена трансляция « android.intent.action.PACKAGE_REMOVED ».
Я надеюсь, что этот подход будет вам полезен 🙂 Поскольку это единственный способ, на мой взгляд, мы можем решить вашу проблему, не укореняя устройство!
[Обновление 1] : предлагаемый подход для проверки отмены задания на удаление:
Его смешно, что раньше у меня была совершенно другая и сложная идея (с участием трансляций, ActivityManager и т. Д. И т. Д.), Но, написав здесь, мне даже подумала другая идея, которая сравнительно проста 🙂
Когда пользователь нажимает кнопку «Удалить» в настройках «Управление приложениями» и после выполнения задач предварительной деинсталляции, вы просто устанавливаете в SharedPreference в своем приложении задание до удаления и готовы к удалению. После этого вам не нужно ни о чем заботиться.
Если пользователь продолжает деинсталлировать -> хорошо и хорошо, как вы уже выполнили требуемые задачи.
Если пользователь наконец нажмет кнопку « Отмена» и уйдет -> не беспокойтесь. Пока пользователь не запустит ваше приложение и не запустит его. Теперь внутри «onStart ()» / «onResume ()» основного действия вашего приложения вы можете проверить значение SharedPreference, и если он был установлен для удаления, это будет означать, что пользователь не завершил деинсталляцию. И теперь вы можете отменить сделанные ранее изменения (реверсирование выполняемых задач перед удалением), чтобы убедиться, что приложение работает отлично!
Другой способ обнаружения удаления приложения – использовать собственный код.
Вам необходимо отслеживать для своего каталога, используя inotify
framework в разветвленном процессе.
Когда он удален, вы можете запустить некоторую системную команду, например. am
которая начинает Intent
PoC такого решения: https://github.com/pelotasplus/ActionAfterUninstall/blob/master/app/src/main/jni/hello-jni.c
Это просто невозможно в Android
У вашего приложения нет возможности узнать, что он удаляется (без изменения ядра). Все файлы, созданные в data / data / your.app.package, автоматически удаляются после установки.
Другим подходом может быть другое приложение, которое проверяет, установлено ли это приложение или нет. Если нет, он может выполнять очистку.
ОБНОВИТЬ
objective ACTION_PACKAGE_REMOVED будет отправлена всем получателям, за исключением ваших собственных. Это подтверждено ЗДЕСЬ .
ОБНОВЛЕНИЕ 2
Просто еще одна мысль.
поскольку я искал это, я обнаружил, что это может быть сделано путем мониторинга logcat для вашего приложения, вот пример монитора logcat
Хорошо, что для мониторинга logcat для того же приложения нам не нужно иметь внедренное устройство
и когда мы читаем каждую запись в logcat, мы можем искать следующую строку
Received broadcast Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.package.name flg=0x8000010 (has extras) }
поскольку это событие получено, мы знаем, что наше приложение теперь будет не установлено
Не пытался
Снова отслеживать logcat от Android Jellybean
Чтобы ваше приложение сохранялось, вам нужно иметь внедренное устройство и его можно установить в системный раздел. После этого вы можете удалить обновления, так как они сохраняются вместе с не-системными приложениями, но это не так, как вырезать и сушить, чтобы удалить его из системы.
Я знаю, что некоторые из них также сэкономит немного данных на системном разделе, если устройства будут сброшены на заводе, но есть также способы заставить диспетчер пакетов оставить ваши сохраненные данные в том случае, если он просто удален ,
Другой вариант – зарегистрировать его как администратора устройства. Как только вы это сделаете, они не смогут удалить его, если они вручную не удалили его статус администратора.
Здесь, похоже, они используют root, а также другие методы. Если не сделать какой-то сумасшедший сложный сервис, который, как представляется, он может иметь, нет законного способа сделать это любым другим способом.
Использование root – это почти стандартная практика для приложений AV / безопасности, подобных этому, без этого у них нет никаких реальных полномочий над любыми другими приложениями, поэтому они очень ограничены. Я думаю, что разрешение SuperUser не отображается, если вы его не установили, поэтому многие люди все еще не знают, что это вариант.