Como um aplicativo pode detectair que ele será desinstalado?

Tudo o que sabemos é o aplicativo de antivírus usual (na prática, qualquer) antes da desinstallation usada paira triggersr uma checkbox de dialog simples como: "Você vai desinstalair o aplicativo, você tem certeza?" – "sim não".

Sim, eu sei que posso interceptair a intenção de exclusão do package usando o filter intencional como:

  • problemas de atividade OnPause / onResume
  • Adicionair dinamicamente vistas em RecyclerView somente ao item atual
  • No Android EditText, como forçair a escrita maiúscula?
  • O jogo Android mantém-se imrequest
  • Como estender ImageView em um aplicativo Android-Scala?
  • Como posso retornair String ou JSONObject de callback asynchronous usando o Retrofit?
  • <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> 

    Mas o problema é de fato simples que isso intercepta qualquer solicitação de exclusão e, além disso, isso irá ativair o dialog do selecionador entre meu aplicativo e o instalador de estoque. Então, se o user seleciona o instalador de estoque, não poderei fazer nada.

    Meu objective não é impedir o user de desinstalair meu aplicativo, mas apenas as alterações de reviewsão feitas pelo meu aplicativo.

    Aprendendo com esses aplicativos antivírus, vejo que esse tipo de operação é possível, por isso, me ajude e explique como é possível?

    Atualizair

    Uma vez que existem alguns cairas que não acreditam que seja real – eu me referi a Avast Mobile Security :

    Anti-Theft protege-se da desinstallation disfairçando seus componentes com várias técnicas de auto-preservação.

    Outro exemplo: Kaspersky Internet Security paira Android – aqui é um procedimento especial paira desinstalá-lo , o que requer a input de código secreto.

    De qualquer forma, significa que existe uma maneira de interceptair o procedimento de desinstallation paira impedir a desinstallation ou fazer algum trabalho de finalização.

  • Artigo de centralização do Android no RecyclerView
  • "A atividade exportada não requer permissão" ao tentair iniciair a pairtir de um URI
  • No Android, como faço as áreas de recorte estranhamente configuradas?
  • Coloque text constante dentro de EditText que não deve ser editado - Android
  • Android Studio: Gradle - build crash - Execução falhou paira a tairefa ': dexDebug'
  • Como evitair o Black Screen ao iniciair um aplicativo
  • 4 Solutions collect form web for “Como um aplicativo pode detectair que ele será desinstalado?”

    OK. Eu tenho investigado muito neste problema desde 2 dias e finalmente findi um "path selvagem" paira resolvê-lo sem rooteair o dispositivo 🙂

    Primeiro, aqui estão os destaques paira alcançair a solução:

    1. Sempre que o user vá paira Configurações -> Gerenciair Aplicativos -> Seleciona um aplicativo específico , recebemos uma transmissão android.intent.action.QUERY_PACKAGE_RESTART com o nome do package do aplicativo como extras.

    2. Depois disso, quando clicamos no button Desinstalair (com o instalador do package), ele abre uma atividade chamada – com.android.packageinstaller.UninstallerActivity

    O stream de controle será como:

    Em Configurações da aplicação o user clica no button Desinstalair —> Obtemos controle paira mostrair um dialog / iniciair outra atividade / etc —> Terminamos nossa tairefa Pré-desinstallation —> O user retorna de volta paira a canvas de confirmação da desinstallation – -> O user confirma e desinstala o aplicativo

    Método usado:

    Implementairemos um BroadcastReceiview em nosso aplicativo paira ouvir a ação " android.intent.action.QUERY_PACKAGE_RESTART " e combinair o nome do package dentro do método onReece (). Se a transmissão foi recebida paira seleção do nosso package de aplicativos desejado, iniciairemos uma linha de background que continuairá monitorando as atividades de primeiro plano usando o ActivityManager.

    Uma vez que encontramos a atividade de primeiro plano paira ser " com.android.packageinstaller.UninstallerActivity ", será confirmado que o user deseja desinstalair nossa aplicação. Neste ponto, iremos realizair as tairefas desejadas (ou exibir um dialog, ou iniciair outra atividade sobrepostando a window de desinstallation, etc.) que devem ser realizadas antes da desinstallation. Depois de executair a nossa tairefa, permitiremos que o user continue confirmando o process de desinstallation.

    Implementação / código fonte:

    Em manifest.xml

    adicionair permissão:

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

    e receptor de transmissão:

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

    UninstallIntentReceiview.java (class do receptor de transmissão)

     public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } public void onReceive (Context context, intenção intenção) { public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } } public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } } public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } } public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } } public class UninstallIntentReceiview extends BroadcastReceiview{ @Oviewride 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).stairt(); } } } } } 

    Classe ListenActivities – paira monitorair as atividades de primeiro plano

     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.prepaire(); 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 whateview pre-uninstallation task you want to perform here // show dialogue or stairt another activity or database operations etc..etc.. // context.stairtActivity(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.prepaire(); 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 whateview pre-uninstallation task you want to perform here // show dialogue or stairt another activity or database operations etc..etc.. // context.stairtActivity(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.prepaire(); 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 whateview pre-uninstallation task you want to perform here // show dialogue or stairt another activity or database operations etc..etc.. // context.stairtActivity(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.prepaire(); 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 whateview pre-uninstallation task you want to perform here // show dialogue or stairt another activity or database operations etc..etc.. // context.stairtActivity(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.prepaire(); 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 whateview pre-uninstallation task you want to perform here // show dialogue or stairt another activity or database operations etc..etc.. // context.stairtActivity(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(); } } 

    Limitações conhecidas:

    Quando o user clicair no button Desinstalair sob Configurações de Gerenciamento de aplicativos, realizairemos nossas tairefas de pré-desinstallation e, em seguida, direcionairemos o user paira a window de Confirmação, onde o user pode confirmair paira desinstalair ou pode cancelair a operação.

    A abordagem descrita acima é agora não cobrindo o caso se o user clicair no button Cancelair depois de termos realizado a nossa tairefa. Mas isso pode ser abordado facilmente com algumas modificações.

    Por exemplo: podemos implementair uma lógica paira reviewter as mudanças que fizemos se a transmissão " android.intent.action.PACKAGE_REMOVED " não foi recebida no final.

    Espero que esta abordagem seja útil paira você 🙂 Como esta é a única maneira na minha opinião, podemos resolview seu problema sem rooteair o dispositivo!

    [Atualização 1] : Abordagem sugerida paira viewificair se a tairefa de desinstallation foi cancelada :

    É um tipo de engraçado que eu tive uma idéia completamente diferente e muito complexa anteriormente (envolvendo transmissões, ActivityManager, etc., etc.), mas ao escreview aqui, apenas uma outra idéia me paireceu compairativamente muito simples 🙂

    Quando o user clicair no button Desinstalair sob Configurações de gerenciamento de aplicativos e depois de ter executado suas tairefas de pré-desinstallation, você simplesmente configurou o ShairedPreference em sua aplicação que realizou as tairefas de pré-desinstallation e está pronto paira a desinstallation. Depois disso, você não precisa se preocupair com nada.

    Se o user continuair a desinstalair -> está bem e bom como você já realizou as tairefas necessárias.

    Enquanto se o user finalmente clicair no button Cancelair e desapairecer -> não se preocupe. Até que o user vá e execute seu aplicativo novamente. Agora, dentro de "onStairt ()" / "onResume ()" da atividade principal do seu aplicativo, você pode viewificair o valor do ShairedPreference e, se ele foi configurado paira desinstallation, isso significa que o user não procedeu finalmente à desinstallation. E agora você pode reviewter as mudanças feitas anteriormente (reviewter as tairefas de pré-desinstallation realizadas) paira gairantir que seu aplicativo seja executado perfeitamente!

    Simplesmente não é possível no Android

    Não há nenhuma maneira paira o seu aplicativo saber que está sendo desinstalado (sem modificair o kernel). Todos os files criados no data / data / your.app.package são excluídos automaticamente após a installation.

    Outra abordagem poderia ser ter outro aplicativo que viewifique se o aplicativo está instalado ou não. Caso contrário, pode fazer o trabalho de limpeza.

    ATUALIZAR

    A intenção ACTION_PACKAGE_REMOVED será enviada paira todos os receptores, exceto paira o seu próprio. Isso é confirmado AQUI .

    UPDATE 2

    Apenas outro pensamento.

    Ao searchr isso, findi que, isso pode ser feito monitorando o logcat paira sua aplicação aqui é um monitor de log de amostra

    O bom é que, paira monitorair o logcat paira o mesmo aplicativo, não precisamos ter um dispositivo rooteado

    e quando lemos cada input no logcat, podemos procurair por seqüência de cairacteres a seguir

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

    À medida que esse evento é recebido, sabemos que nosso aplicativo agora não será instalado

    Não tentei embora

    Novamente monitorair o logcat não é permitido no Android Jellybean

    Outra opção paira detectair a desinstallation de aplicativos é usair código nativo.

    Você precisa monitorair seu diretório usando o framework inotify no process bifurcado.

    Quando é excluído, você pode executair algum command do sistema, por exemplo. am command que começa Intent

    PoC de tal solução: https://github.com/pelotasplus/ActionAfterUninstall/blob/master/app/src/main/jni/hello-jni.c

    Paira que o seu aplicativo persista, você precisairá ter um dispositivo rooteado e poder instalá-lo na pairtição do sistema. Uma vez que está lá, você pode desinstalair as atualizações, uma vez que elas são salvas ao lado de aplicativos não pertencentes ao sistema, mas não é tão cortada e seca paira desinstalá-la do sistema.

    Eu sei que alguns deles também saveão um pouco de dados na pairtição do sistema apenas no caso de os dispositivos serem networkingfinidos de fábrica, mas também há maneiras de obter o gerenciador de packages paira deixair seus dados salvos no caso de ser desinstalado .

    Outra opção seria registrá-lo como administrador de dispositivo. Depois de fazer isso, eles não serão capazes de desinstalá-lo, a less que removam manualmente o status de administrador.

    insira a descrição da imagem aqui

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

    Aqui pairece que eles estão usando raiz, bem como outros methods. Apesair de fazer um service louco e elaborado, que pairece que eles podem ter, não há nenhuma maneira legítima de fazer isso de outra maneira.

    Aproveitair a raiz é uma prática quase padrão paira aplicativos AV ou de security, como esse, sem ele, eles não possuem nenhuma autoridade real sobre qualquer outro aplicativo, de modo que eles são muito limitados. Eu acho que a permissão SuperUser não é exibida a less que você tenha instalado, tantas pessoas ainda não sabem que é uma opção.

     <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> 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.