É possível reiniciar o aplicativo Android depois de chamar ActivityManager.clearApplicationUserData ()

8

Meu aplicativo Android atual precisa ligar

 ActivityManager.clearApplicationUserData()

para simular o usuário limpando o armazenamento de aplicativos

O que funciona bem.

Um efeito colateral da chamada clearApplicationUserData()é que o aplicativo está (compreensivelmente) fechado.

O que oferece uma experiência ruim ao usuário.

Estou tendo dificuldade em reiniciar meu aplicativo depois de ligar clearApplicationUserData().

Eu tentei usar startActivity, Alarm Managercom Pending Intent, Foreground/ Backgroundservice.

Nada funciona.

É impossível reiniciar um aplicativo Android que ligou clearApplicationUserData()?

Hector
fonte
1
Meu palpite é que seu aplicativo seja encerrado no estado parado, como se o usuário tivesse clicado em "Forçar parada". Todos os alarmes, trabalhos, etc. pendentes serão cancelados. "É impossível reiniciar um aplicativo Android que ligou clearApplicationUserData()?" - Duvido que isso seja possível no seu próprio aplicativo. Mostre uma mensagem ao usuário explicando que isso acontecerá antes de chamar esse método, e o usuário poderá reiniciar o aplicativo a partir do iniciador.
CommonsWare
1
Eu acho que é para isso que serve a sua construção .. O Gerenciador de alarmes com intenção pendente, primeiro plano / plano de fundo ficará claro de qualquer maneira .. Se você for usar clearApplicationUserData, esse será o fluxo desejado. Você pode verificar o código-fonte ..
ADM
@CommonsWare existe mesmo assim? Posso ativar o log detalhado (ou similar) para ver o que realmente acontece ao chamar esse método?
Hector
1
Não sei o que você quer dizer com "o que realmente acontece", mas é possível visualizar o Logcat para ver o que está sendo registrado. Se você o estiver visualizando no Android Studio, alterne o filtro de gravidade para "detalhado" e verifique se o menu suspenso final está definido como "Sem filtros" para ver todas as mensagens.
CommonsWare
2
Eu estive em um caminho semelhante no passado. Por fim, foi mais fácil limpar manualmente o banco de dados e as preferências compartilhadas e reiniciar o MainActivity. Se isso for possível, é altamente recomendável! Caso contrário, talvez algo como agendar uma tarefa com WorkManager(que não seja (?) Afetada por dados claros do aplicativo) para iniciar sua atividade?
JakeSteam

Respostas:

4

( 1ª resposta : esta resposta só funciona em situações limitadas. Não é uma resposta completa)

public boolean clearApplicationUserData ()

Descrição

Retorno : truese o aplicativo solicitou com êxito que os dados do aplicativo fossem apagados; falsede outra forma.

Conforme o site de referência indicado, temos um repatriado antes do fechamento do pedido. então, usaremos esse repatriado para reiniciar o aplicativo.

if(ActivityManager.clearApplicationUserData)
{
     doRestart = true;
}

quando Activity onDestroy()e onStop()são chamados de aplicativo de reinicialização.

   @Override
   protected void onDestroy() {
       super.onDestroy();
       if(doRestart){
           Intent intent = new Intent(this, Activity.class);
           this.startActivity(intent);
       }
   }

    @Override
    protected void onStop() {
        super.onStop();
        if(doRestart){
            Intent intent = new Intent(this, Activity.class);
            this.startActivity(intent);
        }
    }

Colocamos a ação de reinicialização em ambos onDestroy() e onStop()para garantir que o aplicativo seja reiniciado novamente.

E também, acho que é uma boa ideia forçar a interrupção da atividade antes que o SO a interrompa.

if(ActivityManager.clearApplicationUserData)
{
     doRestart = true;
     finish(); <= i mean this 
}

é porque, garante onDestroy()e onStop()será invocado.

Mr.AF
fonte
Depois de ligar, ActivityManager.clearApplicationUserData()o processo do aplicativo é morto a força. Nenhuma outra linha de código é executada.
Onik
@Onik você tentou isso? quando o Activity é fechado, sempre onDestroy () é chamado .e também a fonte oficial diz que retorna um booleano, caso contrário, ele deve retornar nulo.
`` Resposta
1
Claro que tentei, por que escreveria o comentário com informações tão detalhadas? Se você tiver outro comportamento de invocação de método, acho que há uma diferença nas implementações da API, o que torna sua versão do SO da solução específica.
Onik
@ Mr.AF obrigado por reservar um tempo para responder. Vou tentar a sua solução, com certeza
Hector
@Onik ver minha próxima resposta :)
Mr.AF 31/12/19
3

Minha sugestão pode parecer trivial, mas você já considerou não ligar ActivityManager.clearApplicationUserData()?

Aqui o que os documentos dizem sobre esse método:

Permite que um aplicativo apague seus próprios dados do disco. Isso equivale à escolha do usuário para limpar os dados do aplicativo na interface do usuário das configurações do dispositivo. Ele apaga todos os dados dinâmicos associados ao aplicativo - seus dados e dados privados em sua área privada no armazenamento externo - mas não remove o aplicativo instalado, nem os arquivos OBB.

Portanto, para imitar esse comportamento, basta limpar os diretórios de armazenamento interno e externo. Não são necessárias permissões para acessar nenhuma delas.

Ilya Gazman
fonte
2

( 2ª resposta : preciso de muito mais contribuição)

Após 8 horas pesquisando no sistema operacional Android e no site para desenvolvedores do Android , a fim de encontrar uma solução para reiniciar a atividade quando clearApplicationUserDatafor chamada. Finalmente, eu seria capaz de encontrar uma boa solução para hackers .

Esta solução parece zidane drible :)

Vamos apresentar a solução. a princípio, clearApplicationUserDatalimpa todas as pistas do aplicativo quando é invocado, como tarefas, notificações, alarmes e etc., portanto, é impossível chamar explicitamente a atividade .

maneira implícita é a única maneira possível de chamar atividade.

Após alguns testes, descobri que o aplicativo manifestregistrado intent-filters não seria removido e eles podem ouvir as transmissões do sistema .

Aproximadamente, 98% das transmissões do sistema não seriam recebidas pelo aplicativo liberado e que 2% restantes poderiam não ser transmitidos muito em breve.

então o que fazer ? hmmm? vamos lá cara, eu preciso encontrar uma solução ...

bingo, preciso acionar algo para que o sistema o transmita <= parece hackear :)

então eu decido escolher WIFI_STATE_CHANGED porque

  • Permissão de acesso fácil
  • Sistema o transmite com atraso <= isso garante que o aplicativo seja fechado antes da transmissão

manifest.xml

<receiver
   android:name=".PackageDataClearedReceiver"
   android:enabled="true"
   android:exported="true">
     <intent-filter android:priority="100">
       <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
       <action android:name="android.net.wifi.STATE_CHANGE" />
     </intent-filter>
 </receiver>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    ActivityManager am;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
                        if (am != null) {
                            ExecutorService pool = Executors.newFixedThreadPool(2);
                            final Collection<Future> futures = new HashSet<Future>();
                            futures.add(pool.submit(new Runnable() {
                                @Override
                                public void run() {
                                    WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                                    wifiManager.setWifiEnabled(true);
                                    wifiManager.setWifiEnabled(false);
                                    am.clearApplicationUserData();
                                }
                            }));
                            for (Future future : futures) {
                                future.isDone();
                            }
                        }

                    }
                }).start();
            }
        });
    }
}

demonstração

insira a descrição da imagem aqui

lembre-se, é apenas um produto mínimo viável que precisa ser mais desenvolvido para torná-lo perfeito.

Mr.AF
fonte
essa abordagem não funcionará para o meu aplicativo, pois eu já detecto alterações no estado WIFI para exibir mensagens para meus usuários. Se eu seguir sua abordagem na 2ª solução toda vez que houver alterações no estado WIFI, iniciarei minha atividade principal
Hector
@ Heitor sim, ele precisa de muito mais desenvolvimento e personalização para sua necessidade, como eu disse, é um produto viável mínimo. Você precisa personalizá-lo
Mr.AF 02 de
@Hector, você precisa colocar condições no Receiver para reiniciar a atividade quando necessário
Mr.AF
0

Espero que isso ainda sirva como ajuda

Pergunta: É impossível reiniciar um aplicativo Android chamado clearApplicationUserData ()? Ans: Não

Depois de chamar clearApplicationUserData (), chame o método abaixo.

private void triggerRebirth(Context context) {
     PackageManager packageManager = context.getPackageManager();
     Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
     ComponentName componentName = intent.getComponent();

     Intent mainIntent = Intent.makeRestartActivityTask(componentName);
     context.startActivity(mainIntent);
     Runtime.getRuntime().exit(0);
}

Feliz codificação.

Whales_Corps
fonte
-1

Limpar os dados do aplicativo no dispositivo por meio da API clearApplicationUserData()redefine o aplicativo como se tivesse acabado de ser instalado. Como você descobriu, todos os alarmes e transmissões registrados no seu aplicativo também são limpos. A maneira mais eficiente de manter seu aplicativo em primeiro plano seria limpar os dados por conta própria, como outros indicaram, em vez de usar a API. Aqui está um exemplo: https://stackoverflow.com/a/9073473/949224


No entanto , se você estiver determinado a usar a API (que garante que todos os dados sejam limpos) e o aplicativo for interrompido à força, tenho uma sugestão:

Crie um aplicativo complementar pequeno que possa ser iniciado imediatamente antes de você limpar os dados do aplicativo. O aplicativo complementar simplesmente o reinicia, possivelmente após um curto período de tempo.

    Intent launchIntent = getPackageManager().getLaunchIntentForPackage("example.com.testrelaunchapp");
    if (launchIntent != null) {
        startActivity(launchIntent);//null pointer check in case package name was not found
    } else {
        Log.w( TAG, "Unable to resolve launch activity of relauncher companion app");
    }

    ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE))
                    .clearApplicationUserData();   

O aplicativo complementar em si precisa ser fechado posteriormente e, idealmente, deve ser oculto da pilha de atividades etc.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final Intent launchIntent = getPackageManager().getLaunchIntentForPackage("example.com.yourmainapp");
    if (launchIntent != null) {
        Handler handler = new Handler(getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i( TAG, "About to act on launchIntent");
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(launchIntent);
                finish();
                System.exit(0);
            }
        }, 1000);
    }    
 }     

Eu já vi esse trabalho com o Android 6.0, mas não há garantias de que ele seria versátil e funcionaria de maneira geral. Seria preciso fazer mais para tornar o aplicativo complementar sem interface do usuário, se desejado, e ficar oculto no iniciador do telefone. Você provavelmente também desejaria agrupar o APK como um arquivo em seu próprio aplicativo e instalá-lo na primeira execução, o que exigiria que o usuário habilitasse a instalação a partir de "Fontes desconhecidas" (loja não Play). Isso pode ser feito através da intenção de obter as configurações corretas do sistema, se necessário, mas os usuários precisariam de uma boa explicação sobre por que isso é necessário.

Então, como eu estava dizendo, a abordagem mais simples é limpar os dados e as permissões do aplicativo.

dr_g
fonte
Eu acho que não é uma solução viável. porque sua solução precisa de pacotes extras instalados, o que torna impossível. e se pudéssemos ter pacotes extras ou aplicativos complementares, haveria várias maneiras de iniciar a atividade.
Mr.AF
Certamente, é possível solicitar ao usuário que instale outro aplicativo por conta própria. A questão é se você deseja esse comportamento como parte de como você opera. Como mencionei, não o recomendaria, mas ainda vale a pena mencionar a idéia em princípio, caso seja útil para outras pessoas.
dr_g 7/01