Ist es möglich, die Android App nach dem Aufruf von ActivityManager.clearApplicationUserData () neu zu starten?

8

Meine aktuelle Android-Anwendung muss anrufen

 ActivityManager.clearApplicationUserData()

um das Löschen des App-Speichers durch den Benutzer zu simulieren

Welches funktioniert gut.

Ein Nebeneffekt des Anrufens clearApplicationUserData() ist, dass die App (verständlicherweise) geschlossen ist.

Das gibt eine schlechte Benutzererfahrung.

Ich habe Schwierigkeiten, meine Anwendung neu zu starten, sobald ich angerufen habe clearApplicationUserData() .

Ich habe versucht startActivity, Alarm Managermit Pending Intent, Foreground/Background Service.

Nichts funktioniert.

Ist es unmöglich, eine aufgerufene Android-App neu zu starten clearApplicationUserData()?

Tyrannisieren
quelle
1
Ich vermute, dass Ihre App im gestoppten Zustand endet, als hätte der Benutzer auf "Stopp erzwingen" geklickt. Alle ausstehenden Alarme, Aufträge usw. werden abgebrochen. "Ist es unmöglich, eine aufgerufene Android-App neu zu starten clearApplicationUserData()?" - Ich bezweifle, dass dies in Ihrer eigenen App möglich ist. Zeigen Sie dem Benutzer eine Nachricht an, in der erläutert wird, dass dies vor dem Aufrufen dieser Methode geschehen wird, und der Benutzer kann die App über den Starter neu starten.
CommonsWare
1
Ich denke, das ist es, wofür es gebaut wurde. Alarm Manager mit ausstehender Absicht, Vordergrund / Hintergrund wird sowieso klar. Wenn Sie verwenden werden, clearApplicationUserDataist dies der gewünschte Ablauf. Sie können den Quellcode dafür auschecken .
ADM
@CommonsWare gibt es überhaupt eine Möglichkeit, die ausführliche Protokollierung (oder ähnliches) zu aktivieren, um zu sehen, was beim Aufrufen dieser Methode tatsächlich passiert?
Hector
1
Ich weiß nicht, was Sie unter "was tatsächlich passiert" verstehen, aber Sie können Logcat anzeigen, um zu sehen, was protokolliert wird. Wenn Sie es in Android Studio anzeigen, schalten Sie den Schweregradfilter auf "ausführlich" und stellen Sie sicher, dass das Dropdown-Menü "Ende" auf "Keine Filter" eingestellt ist, um alle Nachrichten anzuzeigen.
CommonsWare
2
Ich bin in der Vergangenheit einen ähnlichen Weg gegangen. Letztendlich war es einfacher, die Datenbank und die freigegebenen Einstellungen manuell zu löschen und die neu zu starten MainActivity. Wenn dies überhaupt möglich ist, wird es dringend empfohlen! Wenn nicht, vielleicht so etwas wie das Planen einer Aufgabe mit WorkManager(die nicht (?) Von klaren App-Daten beeinflusst wird), um Ihre Aktivität zu starten?
JakeSteam

Antworten:

4

(1. Antwort : Diese Antwort funktioniert nur in begrenzten Situationen. Es ist keine vollständige Antwort.)

public boolean clearApplicationUserData ()

Beschreibung

Rückgabe : trueWenn die Anwendung erfolgreich das Löschen der Daten der Anwendung angefordert hat; falseAndernfalls.

Wie auf der Referenzwebsite angegeben, haben wir einen Rückkehrer, bevor die Bewerbung geschlossen wird. Also werden wir diesen Rückkehrer verwenden, um die App neu zu starten.

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

wenn Aktivität onDestroy()und onStop()werden App neu starten genannt.

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

Wir setzen Neustartaktion in beide onDestroy()und onStop()um sicher App wieder neu gestartet werden zu lassen.

Außerdem halte ich es für eine gute Idee, die Stoppaktivität zu erzwingen, bevor das Betriebssystem sie stoppt.

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

es ist, weil es sicherstellt, dass onDestroy()und onStop()aufgerufen wird.

Mr.AF
quelle
Nach dem Aufruf wird ActivityManager.clearApplicationUserData()der App-Prozess gewaltsam beendet. Es wird keine andere Codezeile ausgeführt.
Onik
@Onik hast du das versucht? Wenn die Aktivität geschlossen wird, wird immer onDestroy () aufgerufen. Außerdem gibt die offizielle Quelle an, dass ein Boolescher Wert zurückgegeben wird, andernfalls sollte void zurückgegeben werden.
Mr.AF
1
Natürlich habe ich versucht, warum sollte ich den Kommentar mit so detaillierten Informationen schreiben? Wenn Sie ein anderes Verhalten beim Aufrufen von Methoden haben, gibt es vermutlich Unterschiede in den API-Implementierungen, wodurch die Version Ihres Lösungsbetriebssystems spezifisch wird.
Onik
@ Mr.AF danke, dass du dir die Zeit genommen hast zu antworten. Ich werde Ihre Lösung auf jeden
Hector
@Onik siehe meine nächste Antwort :)
Mr.AF
3

Mein Vorschlag mag trivial klingen, aber haben Sie in Betracht gezogen, nicht anzurufen? ActivityManager.clearApplicationUserData() ?

Hier ist, was die Dokumentation über diese Methode sagt:

Ermöglicht einer Anwendung, ihre eigenen Daten von der Festplatte zu löschen. Dies entspricht der Auswahl des Benutzers, der die Daten der App über die Benutzeroberfläche der Geräteeinstellungen löscht. Es löscht alle mit der App verknüpften dynamischen Daten - seine privaten Daten und Daten in ihrem privaten Bereich im externen Speicher -, entfernt jedoch weder die installierte Anwendung selbst noch OBB-Dateien.

Um dieses Verhalten nachzuahmen, müssen Sie nur Ihre internen und externen Speicherverzeichnisse löschen. Für den Zugriff auf diese sind keine Berechtigungen erforderlich.

Ilya Gazman
quelle
2

( 2. Antwort : Ich brauche viel mehr Beitrag dazu)

Nach 8 Stunden Recherche in Android OS und Android Developers Website, um eine Lösung zu finden, um die Aktivität beim clearApplicationUserDataAufrufen neu zu starten . Endlich würde ich eine finden können netten / Hacking finden können Lösung finden.

Diese Lösung sieht aus wie Zidane Dribble :)

Lassen Sie uns die Lösung vorstellen. zunächst clearApplicationUserDatalöscht alle Hinweise der Anwendung , wenn wie aufgerufen wird , Aufgaben, Benachrichtigungen, Alarme usw. daher ausdrücklich Aktivität Berufung ist nicht möglich .

Der implizite Weg ist der einzig mögliche Weg, um Aktivitäten aufzurufen.

Nach ein paar Tests stellte ich fest, dass die manifestregistrierte Anwendung intent-filters nicht entfernt werden konnte und sie auf eingehende Systemübertragungen warten können .

Ungefähr 98% der Systemübertragungen würden nicht von einer freigegebenen Anwendung empfangen, und die verbleibenden 2% werden möglicherweise nicht sehr bald ausgestrahlt.

Also, was tun? Hmmm ? Komm schon Mann, ich muss eine Lösung finden ...

Bingo, ich muss etwas auslösen, um es vom System zu senden <= sieht hackend aus :)

Also entscheide ich mich für WIFI_STATE_CHANGED, weil

  • Easy Access-Berechtigung
  • Das System sendet es mit Verzögerung <= Dies stellt sicher, dass die App vor dem Senden geschlossen wird

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

Demo

Geben Sie hier die Bildbeschreibung ein

Denken Sie daran, es ist nur ein Produkt mit minimaler Lebensfähigkeit, das weiterentwickelt werden muss, damit es perfekt funktioniert.

Mr.AF
quelle
Dieser Ansatz funktioniert für meine Anwendung nicht, da ich bereits Änderungen im WIFI-Status feststelle, um Nachrichten für meine Benutzer anzuzeigen. Wenn ich Ihren Ansatz bei jeder Änderung des WIFI-Status in der
Hector
@Hector yup, es muss viel mehr entwickelt und an Ihre Bedürfnisse angepasst werden, da ich sagte, dass es ein Produkt mit minimaler Lebensfähigkeit ist. Sie müssen es anpassen
Mr.AF
@Hector Sie müssen Bedingungen in Receiver einfügen, um die Aktivität bei Bedarf neu zu starten
Mr.AF
0

Hoffentlich dient dies weiterhin als Hilfe

Frage: Ist es unmöglich, eine Android-App mit dem Namen clearApplicationUserData () neu zu starten? Ans: Nein

Wenn Sie clearApplicationUserData () aufrufen, rufen Sie die folgende Methode auf.

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

Viel Spaß beim Codieren.

Whales_Corps
quelle
-1

Durch Löschen der App-Daten auf dem Gerät über die API wird clearApplicationUserData()die App zurückgesetzt, als wäre sie gerade installiert worden. Wie Sie festgestellt haben, werden auch alle mit Ihrer App registrierten Alarme und Sendungen gelöscht. Der effizienteste Weg, um Ihre App im Vordergrund zu halten, besteht darin, die Daten selbst zu löschen, wie andere betont haben, anstatt die API zu verwenden. Hier ist ein Beispiel: https://stackoverflow.com/a/9073473/949224


jedoch , wenn Sie die API sind, bestimmt zu verwenden (die alle Daten tun garantiert werden gelöscht) und die App ist kraft gestoppt, habe ich einen Vorschlag:

Erstellen Sie eine kleine Begleit-App, die unmittelbar vor dem Löschen Ihrer App-Daten gestartet werden kann. Die Companion-App startet Ihre App einfach neu, möglicherweise nach einer kurzen Zeitüberschreitung.

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

Die Begleit-App selbst muss anschließend geschlossen werden und sollte idealerweise vor dem Aktivitätsstapel usw. verborgen sein.

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

Ich habe gesehen, dass dies mit Android 6.0 funktioniert, aber es gibt keine Garantie dafür, dass es vielseitig ist und auf ganzer Linie funktioniert. Es wäre mehr zu tun, um die Companion-App auf Wunsch UI-frei zu machen und vor dem Launcher des Telefons versteckt zu werden. Wahrscheinlich möchten Sie das APK auch als Datei in Ihrer eigenen App bündeln und beim ersten Start installieren. Dazu muss der Benutzer die Installation aus "Unbekannten Quellen" (Nicht-Play-Store) aktivieren. Dies kann bei Bedarf durch Absichten für die richtigen Systemeinstellungen erfolgen, aber Benutzer benötigen eine gute Erklärung, warum dies erforderlich ist.

Wie ich bereits sagte, besteht der einfachere Ansatz darin, die Daten- und App-Berechtigungen selbst zu löschen.

dr_g
quelle
Ich denke, es ist keine praktikable Lösung. weil Ihre Lösung zusätzliche installierte Pakete benötigt, die dies unmöglich machen. und wenn wir in der Lage wären, zusätzliche Pakete oder Begleit-Apps zu haben, gäbe es viele Möglichkeiten, Aktivitäten zu starten.
Mr.AF
Es ist sicherlich möglich, den Benutzer aufzufordern, eine andere App von Ihnen selbst zu installieren. Die Frage ist, ob Sie dieses Verhalten als Teil Ihrer Arbeitsweise wünschen. Wie ich bereits erwähnte, würde ich es nicht empfehlen, aber es ist immer noch wert, die Idee im Prinzip zu erwähnen, falls sie für andere nützlich ist.
dr_g