отримання значень із SharedPreferences після перевстановлення та з дозволомBackup = true за допомогою резервного копіювання Android Auto


9

У мене виникають проблеми з отриманням значень (на пристрої Android 9.0) із спільних налаштувань після того, як я перевстановив додаток і в той час, як у програмі enableBackup = true.

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

Відповідно до цього: https://developer.android.com/guide/topics/data/autobackup

Спільні налаштування слід відновити?

    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();
  • Я увійшов до свого облікового запису Gmail на телефоні (емулятор) (API 27), і, переходячи до Дискового додатка, Резервного копіювання, Даних додатків, я бачу 18 програм, таких як Youtube, Gmail тощо, а також власне додаток.
  • Коли я переходжу до "Налаштування> Система> Резервне копіювання", я бачу ті самі програми, а також власне додаток. Я завантажую додаток, виконується спільний код переробки. Я закриваю додаток і виймаю його з пам'яті. Потім натискаю кнопку "Резервне копіювання зараз":

введіть тут опис зображення

Щоб перевірити, я можу побачити свою програму у списку, і вона отримала резервну копію 0 хвилин тому:

введіть тут опис зображення

Потім я видаляю та перевстановлюю додаток і очікую, що 2 значення (Олена та 12) будуть там. Але вони стираються ...

Я також спробував те саме через командний рядок, але також не працював: 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. Видалити додаток
  2. Перевстановіть додаток і перевірте, чи є ще значення SharedPreferences.
  3. Цінності пішли ...

Здається, поведінка також відрізняється на пристроях Samsung із Samsung Cloud, але поки зосередимось на акції Android.

ОНОВЛЕННЯ:

Він більше не працює, тому що я знизив версію в build.gradle:

build.gradle:
versionCode 70
versionName "1.6.1"

Навіть android:restoreAnyVersion="true"у програмі AndroidManifestвін би працював лише тоді, коли версія не була знижена.


Це може допомогти вам
створити

Привіт @PraveenSP Я хочу використовувати резервну копію Android Auto, а не старішу версію магазину ключів / цінностей.
Джим Клермонц

Відповіді:


1

За замовчуванням система Android створює резервні копії всіх даних за замовчуванням, якщо пристрій підключено до мережі Wi-Fi (якщо користувач пристрою не ввімкнув резервне копіювання даних для мобільних пристроїв), спробуйте перевстановити додаток і підключитися до системи WI-FI, як правило, синхронізація системи Android дані раз на кожні 24 години, якщо є якісь зміни. Ви також можете спробувати вказати власні правила для резервного копіювання, як це.

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

і створити XML-файл і помістити його в каталог res / xml. Всередині файлу додайте правила з елементами та. Наведений нижче зразок створює резервні копії всіх спільних налаштувань, крім 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>`

Сподіваюся, це вирішить ваше питання.


Я просто хочу зберегти sharedprefs, без XML.
Джим Клермонтс

Вищевказаний код - це правила для системи Android для збереження даних на дисках користувача, його не буде збережено як xml, Включити та виключити тег повідомляти системі про те, які дані потрібно синхронізувати та зберегти та які дані потрібно виключити в процесі синхронізації .
Ashish

Я розумію, але я вважаю, що це зайве?
Джим Клермонтс

1
я не думаю, що його непотрібне через те, коли завершено завантаження системи Android, вона перевіряє всі програми програм, налаштовані в маніфесті за замовчуванням, також синхронізується, коли trueBackup відповідає дійсності, але коли ми пишемо правила, система Android зберігає в локальних правилах і пов'язує її з назвою пакета.
Ashish

Я додав вищевказаний код XML, але це не має значення.
Джим Клермонтс

1

Згідно з документом повернення даних вам потрібно створити SharedPreferencesBackupHelper і виконати ці кроки, щоб досягти резервного копіювання SharedPreferences, також потрібно зареєструватися резервного копіювання служби резервного копіювання для вашого випадку


Привіт, я кажу про функцію резервного копіювання Android, а не про службу резервного копіювання Android.
Джим Клермонтс

це стосується лише автоматичного резервного копіювання. для зразка ви можете виконати ці кроки codelabs.developers.google.com/codelabs/android-backup-codelab/…
Damodhar

1

Нехай ця процедура спрацює для вас. Спробуйте створити резервну копію та відновити користувацькі параметри. Це дозволить створити резервну копію ваших уподобань на будь-якому зовнішньому сховищі чи пристрої.

Під час видалення програми користувач повинен створити його назад. Додайте трохи логіки, що якщо файл присутній у Зовнішньому сховищі або пристрої, відновіть його назад.

використовуйте код нижче, щоб створити резервну копію своїх налаштувань.

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

використовувати нижче код для відновлення налаштувань

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

}

потім перезапустіть додаток до того, як ця префренція займе місце

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

Привіт, проблема була в тому, що він не створює резервну копію, коли мій versionCode в build.gradle знижується. Тому це не працювало. Цей великий код не потрібен для зберігання лише простого рядка.
Джим

працював на мене ... врятував мій день ... дякую
unownsp

0

Ви не ввімкнули налаштування автоматичного відновлення, як це було показано в повідомленні консолі. Вам слід перейти до налаштувань системи та включити її. Після цього реставрація могла працювати.

Налаштування -> Резервне копіювання -> Автоматичне відновлення.

До речі, використаний вами маркер невірний. 1573806051616 - мітка часу замість маркера. Маркер повинен відображатися як нижче:

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

Тут XXXXXXXXXXXXXXXXмає бути лексема.


-1

Щоб перевірити відновлення, потрібно виконати команду нижче, не видаляючи додаток. Команда відновлення змусить зупинити додаток, видалити його дані та виконати відновлення, отже, імітуючи функціональність Android AutoBackup:

bmgr restore <TOKEN> <PACKAGE>

TOKENотримується з logcatкоманди при виконанні команди резервного копіювання або з dumpsys backupкоманди. Також ви можете перевірити, dumpsys backupщоб перевірити, чи створено резервну копію.

Більше інформації тут: https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore


Я спробував це і відредагував відповідь, але розділених значень досі немає.
Джим Клермонтс

Існує кілька передумов, які необхідно виконати для резервного копіювання. Перевірте посилання нижче: blog.devknox.io/…
Susheel Tickoo

Передумови виконуються, і це не працює.
Джим Клермонтс

-1

Один із способів зробити це: (Зверніть увагу, це може бути не найкращим способом, але це працює!)

Перш ніж видалити додаток, створіть його назад. Додайте трохи логіки, що якщо файл присутній у Зовнішньому сховищі , відновіть його назад.

Налаштування, що зберігаються в класі SharedPreferences, зберігаються у /data/data//shared_prefs/_preferences.xml - резервна копія проста, вам просто потрібно скопіювати вміст цього файлу у зовнішній сховище:

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

Використовуйте наступний код, щоб відновити налаштування

Але відновлення надає більше труднощів, оскільки файл shared_prefs додаток не підлягає прямому запису, а клас SharedPrefs безпосередньо не піддається його функціональній послідовності з xml. Натомість вам доведеться самостійно розбирати XML і відштовхувати значення назад. На щастя, XML-файл має просту структуру, тому легко перекинути елементи та перетворити їх назад у налаштування.

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

ПРИМІТКА . Потрібен дозвіл на запис і читання у зовнішньому сховищі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.