pobieranie wartości z SharedPreferences po ponownej instalacji i za pomocą allowBackup = true za pomocą Android Auto backup


9

Mam problem z pobraniem wartości (na urządzeniu z Androidem 9.0) z Preferencji udostępnionych po ponownej instalacji aplikacji i po ustawieniu allowBackup = true.

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

Zgodnie z tym: https://developer.android.com/guide/topics/data/autobackup

Wspólne preferencje powinny zostać przywrócone?

    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();
  • Zalogowałem się na swoje konto Gmail na telefonie (emulatorze) (API 27), a kiedy przechodzę do aplikacji Drive, kopii zapasowych, danych aplikacji, widzę 18 aplikacji, takich jak Youtube, Gmail itp., A także moją własną aplikację.
  • Kiedy przechodzę do „Ustawienia> System> Kopia zapasowa”, widzę te same aplikacje i moją własną. Ładuję aplikację, kod sharedprefs jest wykonywany. Zamykam aplikację i usuwam ją z pamięci. A potem naciskam przycisk „Utwórz kopię zapasową teraz”:

wprowadź opis zdjęcia tutaj

Aby zweryfikować, widzę moją aplikację na liście i otrzymała kopię zapasową 0 minut temu:

wprowadź opis zdjęcia tutaj

Następnie usuwam i ponownie instaluję aplikację i oczekuję, że będą tam 2 wartości (Elena i 12). Ale są usuwane ...

Próbowałem również tego samego za pomocą wiersza polecenia, ale również nie działa: 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. Usuń aplikację
  2. Zainstaluj ponownie aplikację i sprawdź, czy wartości SharedPreferences nadal tam są.
  3. Wartości zniknęły ...

Zachowanie wydaje się również różnić na urządzeniach Samsung z Samsung Cloud, ale na razie skupmy się na standardowym Androidzie.

AKTUALIZACJA:

To już nie działało, ponieważ obniżyłem wersję w build.gradle:

build.gradle:
versionCode 70
versionName "1.6.1"

Nawet z android:restoreAnyVersion="true"tym AndroidManifestdziałałoby tylko wtedy, gdy wersja nie została obniżona.



Witaj @PraveenSP Chcę używać kopii zapasowej Android Auto, a nie starszej wersji magazynu kluczy / wartości.
Jim Clermonts

Odpowiedzi:


1

Domyślnie system Android wykonuje kopie zapasowe wszystkich danych domyślnych, jeśli urządzenie jest podłączone do sieci Wi-Fi (jeśli użytkownik urządzenia nie zdecydował się na tworzenie kopii zapasowych danych mobilnych), spróbuj ponownie zainstalować aplikację i połączyć się z WI-FI, zwykle synchronizacja systemu Android dane raz na 24 godziny, jeśli są jakieś zmiany. Możesz także spróbować określić własne reguły tworzenia kopii zapasowych w ten sposób.

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

i utwórz plik xml i umieść go w katalogu res / xml. Wewnątrz pliku dodaj reguły z elementami i. Poniższy przykład tworzy kopię zapasową wszystkich wspólnych preferencji oprócz 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>`

Mam nadzieję, że rozwiąże to Twój problem.


Chcę tylko zapisać sharedprefs, bez XML.
Jim Clermonts,

Powyższy kod jest zasadą dla systemu Android zapisywania danych na dysku użytkownika, nie będzie on zapisywany jako xml, znacznik dołączania i wykluczania powiadamia system, że które dane należy zsynchronizować i zapisać, a które dane należy wykluczyć w operacji synchronizacji .
Ashish srivastava

Rozumiem, ale myślę, że nie jest to konieczne?
Jim Clermonts,

1
nie sądzę, że jest to niepotrzebne, ponieważ po zakończeniu rozruchu systemu Android sprawdza wszystkie reguły aplikacji skonfigurowane w manifeście, domyślnie synchronizuje się, gdy parametr allowBackup jest prawdziwy, ale gdy piszemy reguły, system Android utrzymuje lokalne reguły i kojarzy go z nazwą pakietu.
Ashish srivastava

Dodałem powyższy kod XML, ale to nie robi różnicy.
Jim Clermonts,

1

Zgodnie z dokumentem dotyczącym tworzenia kopii zapasowych danych musisz utworzyć SharedPreferencesBackupHelper i wykonać następujące kroki, aby uzyskać kopię zapasową SharedPreferences, należy również zarejestrować usługi tworzenia kopii zapasowych w swojej sprawie


Witaj, mówię o Android Auto Backup, a nie usłudze Android Backup.
Jim Clermonts,

dotyczy tylko automatycznej kopii zapasowej. dla przykładu możesz wykonać następujące kroki codelabs.developers.google.com/codelabs/android-backup-codelab/…
Damodhar

1

Niech ta procedura zadziała dla Ciebie. Spróbuj wykonać kopię zapasową i przywrócić współdzielone preferencje użytkownika. Spowoduje to utworzenie kopii zapasowej preferencji na dowolnym Zewnętrznym urządzeniu magazynującym lub urządzeniu.

Po odinstalowaniu aplikacji użytkownik powinien ją ponownie wykonać. Dodaj logikę, że jeśli plik jest obecny w pamięci zewnętrznej lub urządzeniu, przywróć go z powrotem.

użyj poniższego kodu, aby wykonać kopię zapasową swoich preferencji.

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

użyj poniższego kodu, aby przywrócić preferencje

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

}

następnie uruchom ponownie aplikację, zanim te preferencje zostaną uwzględnione

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

Witaj, problem polegał na tym, że nie tworzy kopii zapasowej, gdy moja wersjaCode w build.gradle jest obniżona. Właśnie dlatego to nie działało. Taki kod nie jest potrzebny do przechowywania tylko prostego ciągu.
Jim Clermonts,

pracował dla mnie ... uratował mi dzień ... dziękuję
unownsp

0

Nie włączono ustawień automatycznego przywracania, jak pokazano w komunikacie konsoli. Powinieneś przejść do ustawień systemu i włączyć go. Następnie przywrócenie może działać.

Ustawienia -> Kopia zapasowa -> Automatyczne przywracanie.

BTW, użyty token jest nieprawidłowy. 1573806051616 jest znacznikiem czasu zamiast tokena. Token powinien wyglądać jak poniżej:

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

Tutaj XXXXXXXXXXXXXXXXpowinien być token.


-1

Aby przetestować przywracanie, musisz uruchomić poniższe polecenie bez usuwania aplikacji. Polecenie przywracania wymusi zatrzymanie aplikacji, wyczyszczenie danych i wykonanie przywracania, symulując w ten sposób funkcjonalność Android AutoBackup:

bmgr restore <TOKEN> <PACKAGE>

TOKENjest pobierany z logcatpolecenia podczas uruchamiania polecenia tworzenia kopii zapasowej lub z dumpsys backuppolecenia. Możesz także sprawdzić, dumpsys backupczy weryfikacja została utworzona.

Więcej informacji tutaj: https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore


Próbowałem tego i zredagowałem odpowiedź, ale wartości sharedpref wciąż zniknęły.
Jim Clermonts

Aby wykonać kopię zapasową, należy spełnić pewne warunki wstępne. Proszę sprawdzić poniższy link :: blog.devknox.io/…
Susheel Tickoo

Warunki wstępne są spełnione i nie działa.
Jim Clermonts

-1

Można to zrobić w następujący sposób: (Uwaga, może nie być to najlepszy sposób, ale działa!)

Przed odinstalowaniem aplikacji wykonaj kopię zapasową. Dodaj logikę, że jeśli plik jest obecny w pamięci zewnętrznej , przywróć go z powrotem.

Preferencje przechowywane w klasie SharedPreferences są zapisywane w /data/data//shared_prefs/_preferences.xml - tworzenie kopii zapasowej jest łatwe, wystarczy skopiować zawartość tego pliku do pamięci zewnętrznej:

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

Użyj następującego kodu, aby przywrócić preferencje

Ale przywracanie stanowi większe wyzwanie, ponieważ aplikacja shared_prefs nie jest bezpośrednio zapisywalna przez aplikację, a klasa SharedPrefs nie udostępnia bezpośrednio swojej funkcji do serializacji z xml. Zamiast tego musisz samodzielnie przeanalizować XML i wcisnąć wartości z powrotem. Na szczęście plik XML ma prostą strukturę, więc łatwo jest zapętlić elementy i zamienić je z powrotem w preferencje.

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

UWAGA : Wymagane jest zezwolenie na zapis i odczyt pamięci zewnętrznej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.