recupero di valori da SharedPreferences dopo la reinstallazione e con allowBackup = true utilizzando il backup automatico di Android


9

Ho problemi a recuperare i valori (su un dispositivo Android 9.0) dalle Preferenze condivise dopo aver reinstallato l'App e pur avendo allowBackup = true.

<manifest ... >
    ...
    <application android:allowBackup="true" ... >
        ...
    </application>
</manifest>

Secondo questo: https://developer.android.com/guide/topics/data/autobackup

Le preferenze condivise dovrebbero essere ripristinate?

    SharedPreferences prefs = getSharedPreferences("TEST", MODE_PRIVATE);
    String name = prefs.getString("name", "No name defined");//"No name defined" is the default value.
    int idName = prefs.getInt("idName", 0); //0 is the default value.

    SharedPreferences.Editor editor = getSharedPreferences("TEST", MODE_PRIVATE).edit();
    editor.putString("name", "Elena");
    editor.putInt("idName", 12);
    editor.apply();
  • Ho effettuato l'accesso al mio account Gmail sul telefono (emulatore) (API 27) e quando accedo all'app Drive, backup, dati app, vedo 18 app come Youtube, Gmail ecc. E anche la mia app.
  • Quando vado in "Impostazioni> Sistema> Backup" vedo le stesse app e anche la mia app. Carico l'app, il codice sharedprefs viene eseguito. Chiudo l'app e la rimuovo dalla memoria. E poi premo il pulsante "Backup ora":

inserisci qui la descrizione dell'immagine

Per verificare posso vedere la mia app nell'elenco e ha ottenuto il backup 0 minuti fa:

inserisci qui la descrizione dell'immagine

Quindi rimuovo e reinstallo l'App e mi aspetto che i 2 valori (Elena e 12) siano lì. Ma vengono cancellati ...

Ho anche provato lo stesso tramite riga di comando, ma anche non funziona: https://developer.android.com/guide/topics/data/testingbackup.html#Preparing

adb shell
dreamlte:/ $ bmgr enabled
Backup Manager currently enabled
dreamlte:/ $ bmgr list transports
    android/com.android.internal.backup.LocalTransport
    com.google.android.gms/.backup.migrate.service.D2dTransport
* com.google.android.gms/.backup.BackupTransportService
dreamlte:/ $ bmgr backupnow my.package.name
Running incremental backup for 1 requested packages.
Package @pm@ with result: Success
Package nl.dagelijkswoord.android with progress: 1536/309248
Package nl.dagelijkswoord.android with result: Success
Backup finished with result: Success

dreamlte:/ $ dumpsys backup
Backup Manager is enabled / provisioned / not pending init
Auto-restore is disabled
No backups running
Last backup pass started: 1573804513565 (now = 1573806675410)
  next scheduled: 1573819001046
...
1573806051616 : my.package.name

dreamlte:/ $ bmgr restore 1573806051616 my.package.name                                                                                                            
No matching restore set token.  Available sets:
  35e84268c94b7d9c : SM-G950F
  3a8e32898034f8af : SM-G950F
  3e2610c4ea45fb96 : Nexus 5X
done

dreamlte:/ $ bmgr restore 35e84268c94b7d9c my.package.name                                                                                                         
Scheduling restore: SM-G950F
restoreStarting: 1 packages
onUpdate: 0 = my.package.name 
restoreFinished: 0
done
  1. Rimuovi app
  2. Reinstalla l'app e controlla se i valori di SharedPreferences sono ancora presenti.
  3. I valori sono andati ...

Il comportamento sembra differire anche sui dispositivi Samsung con Samsung Cloud, ma per ora concentriamoci su stock Android.

AGGIORNARE:

Non funzionava più perché ho eseguito il downgrade della versione in build.gradle:

build.gradle:
versionCode 70
versionName "1.6.1"

Anche con android:restoreAnyVersion="true"in AndroidManifestfunzionerebbe solo quando la versione non è stata declassata.


Questo potrebbe aiutarti a backup-sharedpreferences-in-android
PraveenSP

Ciao @PraveenSP Voglio utilizzare il backup di Android Auto e non la versione precedente dell'archivio chiavi / valori.
Jim Clermonts,

Risposte:


1

Per impostazione predefinita, il sistema Android esegue il backup di tutti i dati predefiniti se il dispositivo è connesso a una rete Wi-Fi (se l'utente del dispositivo non ha aderito ai backup dei dati mobili), provare a reinstallare l'app e connettersi con WI-FI, di solito la sincronizzazione del sistema Android dati una volta ogni 24 ore se ci sono cambiamenti. Puoi anche provare a specificare le tue regole per il backup in questo modo.

`<application 
 android:fullBackupContent="@xml/backup_rules">
</application>`

e crea un file xml e mettilo nella directory res / xml. All'interno del file, aggiungi le regole con gli elementi e. L'esempio seguente esegue il backup di tutte le preferenze condivise tranne device.xml.

`<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
</full-backup-content>`

Spero che risolverà il tuo problema.


Voglio solo salvare sharedprefs, no xml.
Jim Clermonts,

Il codice sopra è regole per il sistema Android per salvare i dati sull'unità utente, non sarà salvato come xml, Includi ed escludi tag notifica al sistema quali dati devono sincronizzare e salvare e quali dati devono escludere nell'operazione di sincronizzazione .
Ashish srivastava,

Capisco ma non è necessario, penso?
Jim Clermonts,

1
non penso, è inutile perché quando il sistema Android si è complimentato, controlla tutte le regole delle app configurate in manifest per impostazione predefinita, si sincronizza anche quando allowBackup è vero, ma quando scriviamo regole il sistema Android mantiene le regole locali e lo associa al nome del pacchetto.
Ashish srivastava,

Ho aggiunto il codice XML sopra ma non fa differenza.
Jim Clermonts,

1

Come da documento di back-up dei dati, è necessario creare SharedPreferencesBackupHelper e seguire questi passaggi per ottenere il backup di SharedPreferences, inoltre è necessario registrare i servizi di backup per il proprio caso


Ciao, sto parlando di Android Auto Backup, non del servizio di backup Android.
Jim Clermonts,

è correlato solo al backup automatico. per l'esempio puoi seguire questi passaggi codelabs.developers.google.com/codelabs/android-backup-codelab/…
Damodhar,

1

Possa questa procedura funzionare per te. Prova a eseguire il backup e il ripristino delle preferenze condivise di un utente. Questo eseguirà il backup delle tue preferenze su qualsiasi dispositivo di archiviazione esterno.

Quando l'utente disinstalla l'app, l'utente dovrebbe ripristinarla. Aggiungi una logica che, se il file è presente nella memoria esterna o nel dispositivo, ripristinalo.

utilizzare il codice seguente per eseguire il backup delle preferenze.

public static void backupUserPrefs(Context context) {
    final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
    final File backupFile = new File(context.getExternalFilesDir(null),
        "preferenceBackup.xml");
    String error = "";

    try {
        FileChannel src = new FileInputStream(prefsFile).getChannel();
        FileChannel dst = new FileOutputStream(backupFile).getChannel();

        dst.transferFrom(src, 0, src.size());

        src.close();
        dst.close();

        Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
        toast.show();
        return;
    } catch (FileNotFoundException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (IOException e) {
        error = e.getMessage();
        e.printStackTrace();
    }

utilizzare il codice seguente per ripristinare le preferenze

public static boolean restoreUserPrefs(Context context) {
    final File backupFile = new File(context.getExternalFilesDir(null),
        "preferenceBackup.xml");
    String error = "";

    try {

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        Editor editor = sharedPreferences.edit();

        InputStream inputStream = new FileInputStream(backupFile);

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

        Document doc = docBuilder.parse(inputStream);
        Element root = doc.getDocumentElement();

        Node child = root.getFirstChild();
        while (child != null) {
            if (child.getNodeType() == Node.ELEMENT_NODE) {

                Element element = (Element) child;

                String type = element.getNodeName();
                String name = element.getAttribute("name");

                // In my app, all prefs seem to get serialized as either "string" or
                // "boolean" - this will need expanding if yours uses any other types!    
                if (type.equals("string")) {
                    String value = element.getTextContent();
                    editor.putString(name, value);
                } else if (type.equals("boolean")) {
                    String value = element.getAttribute("value");
                    editor.putBoolean(name, value.equals("true"));
                }
            }

            child = child.getNextSibling();

        }

        editor.commit();

        Toast toast = Toast.makeText(context, "Restored user prefs from " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
        toast.show();

        return true;

    } catch (FileNotFoundException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (SAXException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (IOException e) {
        error = e.getMessage();
        e.printStackTrace();
    }

    Toast toast = Toast.makeText(context, "Failed to restore user prefs from " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
    toast.show();

    return false;
}


    Toast toast = Toast.makeText(context, "Failed to Back up user prefs to " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
    toast.show();

}

quindi riavvia l'app prima che queste prefrence prendano piede

if (restoreUserPrefs(context)) {
    // Restart              
    AlarmManager alm = (AlarmManager) context.getSystemService(
    Context.ALARM_SERVICE);
    alm.set(AlarmManager.RTC,
    System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
    new Intent(context, MainActivityName.class), 0));
    android.os.Process.sendSignal(android.os.Process.myPid(),
    android.os.Process.SIGNAL_KILL);
}

Salve, il problema era che non esegue il backup quando il mio versionCode in build.gradle viene declassato. Ecco perché non funzionava. Questo codice non è necessario per memorizzare solo una stringa semplice.
Jim Clermonts,

ha funzionato per me ... mi ha salvato la giornata ... grazie
unspsp

0

Non hai attivato le impostazioni di ripristino automatico come mostrato nel messaggio della console. Dovresti andare alle impostazioni di sistema e accenderlo. Successivamente, il restauro potrebbe funzionare.

Impostazioni -> Backup -> Ripristino automatico.

A proposito, il token che hai usato non è corretto. 1573806051616 è un timestamp anziché il token. Il token dovrebbe apparire come di seguito:

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

Qui, XXXXXXXXXXXXXXXXdovrebbe essere il token.


-1

Per testare il ripristino, è necessario eseguire il comando seguente senza rimuovere l'app. Il comando di ripristino forzerà l'arresto dell'app, cancellerà i suoi dati ed eseguirà il ripristino simulando così la funzionalità di AutoBackup Android:

bmgr restore <TOKEN> <PACKAGE>

TOKENviene recuperato dal logcatcomando quando si esegue il comando di backup o dal dumpsys backupcomando. Inoltre, è possibile controllare dumpsys backupper verificare che il backup sia stato creato.

Maggiori informazioni qui: https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore


Ho provato questo e ho modificato la risposta ma i valori di sharedpref sono ancora spariti.
Jim Clermonts,

Ci sono alcune condizioni preliminari da soddisfare per il backup. Si prega di controllare il link sottostante :: blog.devknox.io/…
Susheel Tickoo

Le condizioni preliminari sono soddisfatte e non funziona.
Jim Clermonts,

-1

Un modo per farlo è il seguente, (Nota, questo potrebbe non essere il modo migliore, ma funziona!)

Prima di disinstallare l'app, ripristinarla. Aggiungi un po 'di logica che, se il file è presente nella memoria esterna , ripristinalo.

Le preferenze memorizzate nella classe SharedPreferences vengono salvate in /data/data//shared_prefs/_preferences.xml - il backup è semplice, devi solo copiare il contenuto di questo file su un archivio esterno:

public static void backupUserPrefs(Context context) {
final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
final File backupFile = new File(context.getExternalFilesDir(null),
    "preferenceBackup.xml");
String error = "";

try {
    FileChannel src = new FileInputStream(prefsFile).getChannel();
    FileChannel dst = new FileOutputStream(backupFile).getChannel();

    dst.transferFrom(src, 0, src.size());

    src.close();
    dst.close();

    Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
    toast.show();
    return;
} catch (FileNotFoundException e) {
    error = e.getMessage();
    e.printStackTrace();
} catch (IOException e) {
    error = e.getMessage();
    e.printStackTrace();
}

Utilizzare il seguente codice per ripristinare la preferenza

Ma il ripristino offre una sfida maggiore, poiché il file shared_prefs non è direttamente scrivibile dall'app e la classe SharedPrefs non espone direttamente la sua funzionalità alla serializzazione da xml. Invece devi analizzare tu stesso l'XML e reinserire i valori. Per fortuna il file XML ha una struttura semplice, quindi è facile passare in rassegna gli elementi e trasformarli in preferenze.

if (restoreUserPrefs(context)) {
// Restart              
AlarmManager alm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alm.set(AlarmManager.RTC,
System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
new Intent(context, MainActivityName.class), 0));
android.os.Process.sendSignal(android.os.Process.myPid(),
android.os.Process.SIGNAL_KILL);
}

NOTA : sono richiesti i permessi di scrittura e lettura della memoria esterna.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.