October 8, 2018

Импорт и экспорт данных приложения. Теория.

@VolfsChannel

Порой нам бывает необходимо восстановить некоторые настройки приложения. Это просто делается вручную, но что если в приложении десятки, а то и сотни независимых настроек? На многих устройствах нет рута, с adb не каждый разберется. Так что же делать? Сейчас узнаем.

Данный код будет работать при 2-х условиях:

  • Наличие разрешения на запись
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

  • В настройках системы тоже должен быть предоставлен доступ

Создадим класс BackupFactory.java:

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;


public class BackupFactory {
    // Экспорт БД
    public static void exportDb(Activity activity, String dbFiles) {
        ContextWrapper contextWrapper = new ContextWrapper(activity);
		// Преобразование строки в массив
        String[] dbs = dbFiles.split(",");
		// Экспорт каждого отдельного файла
        for (String db : dbs) {
            File expDb = contextWrapper.getDatabasePath(db);
            exportFile(expDb, activity);
        }
    }

    //Импорт БД
    public static void importDb(Activity activity,  String dbFiles) {
        ContextWrapper contextWrapper = new ContextWrapper(activity);
		// Преобразование строки в массив
        String[] dbs = dbFiles.split(",");
		// Импорт каждого отдельного файла
        for (String db : dbs) {
            File expDb = contextWrapper.getDatabasePath(db);
            importFile(expDb, activity);
        }
    }

    // Экспорт файла настроек
    public static void exportPrefs(Activity activity) {
        ApplicationInfo info = activity.getApplicationInfo();
        String dir = new ContextWrapper(activity).getCacheDir().getParent();
        File prefs = new File(dir, "shared_prefs/" + info.packageName + "_preferences.xml");
        exportFile(prefs, activity);
    }

    // Импорт файла настроек
    public static void importPrefs(Activity activity) {
        ApplicationInfo info = activity.getApplicationInfo();
        String dir = new ContextWrapper(activity).getCacheDir().getParent();
        File prefs = new File(dir, "shared_prefs/" + info.packageName + "_preferences.xml");
        importFile(prefs, activity);
    }

    // Экспорт файла
    private static void exportFile(File file, Activity activity) {
        // Если нет разрешения на запись
        if (!isExternalStorageWritable() || !canWriteStorage(activity)) {
            Toast.makeText(activity, "Нет разрешения на чтение/запись!", Toast.LENGTH_SHORT).show();
            return;
        }
        File backup = new File(getFolder(), file.getName());
		// Перезаписываем существующий файл
        if (backup.exists()) {
            backup.delete();
        }
        if (copy(file, backup)) {
            Toast.makeText(activity, "Успешно!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(activity, "Ошибка!", Toast.LENGTH_SHORT).show();
        }
    }

    // Импорт файла
    private static void importFile(File file, Activity activity) {
        // Если нет разрешения на запись
        if (!isExternalStorageReadable() || !canWriteStorage(activity)) {
            Toast.makeText(activity, "Нет разрешения на чтение/запись!", Toast.LENGTH_SHORT).show();
            return;
        }
        File backup = new File(getFolder(), file.getName());
        if (!backup.exists()) {
            Toast.makeText(activity, "Файлы бэкапа отсутствуют!", Toast.LENGTH_LONG).show();
            return;
        }
        if (file.exists()) {
            file.delete();
        }
		// Всё хорошо
        if (copy(backup, file)) {
            Toast.makeText(activity, "Успешно!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(activity, "Ошибка!", Toast.LENGTH_SHORT).show();
        }
    }

    // Получение пути к папке бэкапов
    // [SDCARD]/Documents/backup/

    private static File getFolder() {
        File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "backup");
        if (!folder.exists()) {
            folder.mkdirs();
        }
        return folder;
    }

    // Проверка на возможность записи
    private static boolean canWriteStorage(Activity activity) {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
                activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        == PackageManager.PERMISSION_GRANTED;
    }

    // Копирование файлов тудым-сюдым
    private static boolean copy(File inFile, File outFile) {
        FileInputStream in;
        FileOutputStream out;
        try {
            in = new FileInputStream(inFile);
            out = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();

            // write the output file
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            Log.e("BackupFactory", e.getMessage());
        }
        return false;
    }

    /* Checks if external storage is available for read and write */
    private static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

    /* Checks if external storage is available to at least read */
    private static boolean isExternalStorageReadable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
    }
	

Я добавил комментарии к коду. Основных метода 4 - импорт/экспорт БД, импорт/экспорт настроек. Файлов БД может быть несколько, указывать их надо через запятую "test.db,sec.db" etc.

Теперь попробуем написать...[Продолжение следует]