recuperar valores de SharedPreferences después de reinstalar y con allowBackup = true usando la copia de seguridad automática de Android

9

Tengo problemas para recuperar los valores (en un dispositivo Android 9.0) de las Preferencias compartidas después de reinstalar la aplicación y tener allowBackup = true.

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

De acuerdo con esto: https://developer.android.com/guide/topics/data/autobackup

Las preferencias compartidas deben ser restauradas?

    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();
  • He iniciado sesión en mi cuenta de Gmail en el teléfono (emulador) (API 27) y al acceder a la aplicación Drive, copias de seguridad, datos de la aplicación, veo 18 aplicaciones como Youtube, Gmail, etc. y también mi propia aplicación.
  • Cuando voy a "Configuración> Sistema> Copia de seguridad", veo las mismas aplicaciones y también mi propia aplicación. Cargo la aplicación, se ejecuta el código sharedprefs. Cierro la aplicación y la elimino de la memoria. Y luego presiono el botón "Respaldar ahora":

ingrese la descripción de la imagen aquí

Para verificar, puedo ver mi aplicación en la lista y obtuvo una copia de seguridad hace 0 minutos:

ingrese la descripción de la imagen aquí

Luego elimino y reinstalo la aplicación y espero que los 2 valores (Elena y 12) estén allí. Pero se borran ...

También intenté lo mismo a través de la línea de comandos, pero tampoco funcionó: 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. Eliminar aplicaciones
  2. Vuelva a instalar la aplicación y compruebe si los valores de SharedPreferences siguen ahí.
  3. Los valores se han ido ...

El comportamiento también parece diferir en los dispositivos Samsung con Samsung Cloud, pero por ahora centrémonos en el stock de Android.

ACTUALIZAR:

Ya no funcionaba porque degradé la versión en build.gradle:

build.gradle:
versionCode 70
versionName "1.6.1"

Incluso con android:restoreAnyVersion="true"el AndroidManifestsolo funcionaría cuando la versión no fuera degradada.

Jim Clermonts
fuente
Esto podría ayudarlo a hacer backup-sharedpreferences-in-android
PraveenSP
Hola @PraveenSP Quiero usar la copia de seguridad automática de Android y no la versión anterior del almacén de claves / valores.
Jim Clermonts

Respuestas:

1

De manera predeterminada, el sistema Android realiza una copia de seguridad de todos los datos predeterminados si el dispositivo está conectado a una red Wi-Fi (si el usuario del dispositivo no ha optado por las copias de seguridad de datos móviles), intente reinstalar la aplicación y conectarse con WI-FI, generalmente la sincronización del sistema Android datos una vez cada 24 horas si hay algún cambio. También puede intentar especificar sus propias reglas para copias de seguridad como esta.

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

y cree un archivo xml y póngalo en el directorio res / xml. Dentro del archivo, agregue reglas con los elementos y. El siguiente ejemplo respalda todas las preferencias compartidas, excepto 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>`

Espero que resuelva tu problema.

Ashish srivastava
fuente
Solo quiero guardar sharedprefs, no xml.
Jim Clermonts
El código anterior es reglas para que el sistema Android guarde datos en la unidad del usuario, no se guardará como xml, la etiqueta Incluir y Excluir notifica al sistema qué datos deben sincronizarse y guardarse y qué datos deben excluirse en la operación de sincronización .
Ashish srivastava
Entiendo pero es innecesario, creo?
Jim Clermonts
1
No creo que sea innecesario porque cuando se completó el arranque del sistema Android, verifica todas las reglas de las aplicaciones configuradas en manifiesto de forma predeterminada, también se sincroniza cuando allowBackup es verdadero, pero cuando escribimos reglas, el sistema Android mantiene las reglas locales y lo asocia con el nombre del paquete.
Ashish srivastava
He agregado el código XML anterior pero no hace la diferencia.
Jim Clermonts
1

De acuerdo con el documento de respaldo de datos, debe crear SharedPreferencesBackupHelper y seguir estos pasos para lograr una copia de respaldo de SharedPreferences también debe registrar los servicios de respaldo para su caso

Damodhar
fuente
Hola, estoy hablando de la Copia de seguridad automática de Android, no del servicio de copia de seguridad de Android.
Jim Clermonts
solo está relacionado con la copia de seguridad automática. para la muestra, puede seguir estos pasos codelabs.developers.google.com/codelabs/android-backup-codelab/…
Damodhar
1

Que este procedimiento funcione para usted. Intente hacer una copia de seguridad y restaurar las Preferencias compartidas de un usuario. Esto respaldará su preferencia a cualquier dispositivo o almacenamiento externo.

Cuando el usuario desinstala la aplicación, el usuario debe recuperarla. Agregue algo de lógica que si el archivo está presente en el Almacenamiento externo o dispositivo, restaure de nuevo.

use el código a continuación para respaldar su preferencia.

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

use el siguiente código para restaurar la preferencia

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

}

luego reinicie su aplicación antes de que estas preferencias se apoderen

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);
}
UD ..
fuente
Hola, el problema era que no se hacía una copia de seguridad cuando se bajaba mi versionCode en build.gradle. Por eso no estaba funcionando. Este código no es necesario para almacenar solo una cadena simple.
Jim Clermonts
funcionó para mí ... salvó mi día ... gracias
unownsp
0

No activó la configuración de Restauración automática como se muestra en el mensaje de la consola. Debe ir a la configuración del sistema y encenderlo. Después de eso, la restauración podría funcionar.

Configuración -> Copia de seguridad -> Restauración automática.

Por cierto, el token que usaste no es correcto. 1573806051616 es una marca de tiempo en lugar del token. El token debería aparecer de la siguiente manera:

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

Aquí, el XXXXXXXXXXXXXXXXdebería ser el token.

primer año
fuente
-1

Para probar la restauración, debe ejecutar el siguiente comando sin eliminar su aplicación. El comando de restauración forzará la detención de la aplicación, borrará sus datos y realizará la restauración simulando así la funcionalidad de Android AutoBackup:

bmgr restore <TOKEN> <PACKAGE>

TOKENse recupera del logcatcomando cuando se ejecuta el comando de copia de seguridad o del dumpsys backupcomando. También puede verificar dumpsys backuppara verificar que se creó la copia de seguridad.

Más información aquí: https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore

ahasbini
fuente
Intenté esto y edité la respuesta, pero los valores de preferencias compartidas aún se han ido.
Jim Clermonts
Hay algunas condiciones previas que deben cumplirse para la copia de seguridad. Por favor, consulte el siguiente enlace :: blog.devknox.io/…
Susheel Tickoo
Se cumplen las condiciones previas y no funciona.
Jim Clermonts
-1

Una forma de hacerlo es la siguiente: (Tenga en cuenta que esta puede no ser la mejor manera, ¡pero funciona!)

Antes de desinstalar la aplicación, vuelva a realizarla. Agregue algo de lógica que, si el archivo está presente en el almacenamiento externo , restaure de nuevo.

Las preferencias almacenadas en la clase SharedPreferences se guardan en /data/data//shared_prefs/_preferences.xml: la copia de seguridad es fácil, solo necesita copiar el contenido de este archivo en un almacenamiento externo:

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

Use el siguiente código para restaurar la preferencia

Pero la restauración ofrece más desafíos, ya que la aplicación no puede escribir directamente el archivo shared_prefs, y la clase SharedPrefs no expone directamente su funcionalidad para serializar desde xml. En su lugar, debe analizar el XML usted mismo y volver a introducir los valores. Afortunadamente, el archivo XML tiene una estructura sencilla, por lo que es fácil recorrer los elementos y convertirlos nuevamente en preferencias.

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 : Se requiere permiso de escritura y lectura de almacenamiento externo.

ChandraMouli Poreddy
fuente