From 485617aedf0874d562c2b82aae2f3cf7614498ed Mon Sep 17 00:00:00 2001 From: rafi0101 <43086854+rafi0101@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:36:18 +0200 Subject: [PATCH] FIX readme syntax and formatted --- README.md | 448 ++++++++++++++++++++++++++---------------------------- 1 file changed, 217 insertions(+), 231 deletions(-) diff --git a/README.md b/README.md index 81cf699..97d3155 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Android-Room-Database-Backup - ![Build](https://github.com/rafi0101/Android-Room-Database-Backup/workflows/Android%20CI/badge.svg) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/de.raphaelebner/roomdatabasebackup/badge.svg)](https://maven-badges.herokuapp.com/maven-central/de.raphaelebner/roomdatabasebackup) [![Room Version](https://img.shields.io/badge/room_version-2.6.1-orange)](https://developer.android.com/jetpack/androidx/releases/room#2.6.1) @@ -17,30 +16,29 @@ Simple tool to backup and restore your room database in Android -Features ---------- -* Create simple backups of your room database -* Encrypt the backup file with AES encryption -* Save the backup to any type of storage (some types are in beta) -* Material design -* Written in Kotlin - -Content ------------ -* [Features](#Features) -* [Changelog](#Changelog) -* [Getting started](#Getting-started) -* [Usage](#Usage) -* [Sample app](#Sample-app) -* [Developed by](#Developed-by) -* [License](#License) - -Changelog ------------ +## Features + +- Create simple backups of your room database +- Encrypt the backup file with AES encryption +- Save the backup to any type of storage (some types are in beta) +- Material design +- Written in Kotlin + +## Content + +- [Features](#Features) +- [Changelog](#Changelog) +- [Getting started](#Getting-started) +- [Usage](#Usage) +- [Sample app](#Sample-app) +- [Developed by](#Developed-by) +- [License](#License) + +## Changelog + [Changelog and Upgrading notes](CHANGELOG.md) -Getting started ------------ +## Getting started Android-Room-Database-Backup library is pushed to [Maven Central](https://central.sonatype.com/artifact/de.raphaelebner/roomdatabasebackup/1.0.0-beta14/versions) @@ -54,29 +52,26 @@ implementation 'de.raphaelebner:roomdatabasebackup:1.0.0-beta14' **If the version makes any technical problems please feel free to contact me. I made some changes in Gradle/Kotlin DSL and not sure if everything is working as excepted** -Usage ------------ +## Usage -* [Properties](#Properties) -* [Exit Codes](#Exit-Codes) -* [Example Activity (Kotlin and Java)](#example-activity-kotlin-and-java) -* [Example Fragment (Java and Kotlin)](#example-fragment-kotlin-and-java) +- [Properties](#Properties) +- [Exit Codes](#Exit-Codes) +- [Example Activity (Kotlin and Java)](#example-activity-kotlin-and-java) +- [Example Fragment (Java and Kotlin)](#example-fragment-kotlin-and-java) ### Properties **Required** -* Current context +- Current context **Attention** - Must be declared outside of an onClickListener before lifecycle state changes to started + Must be declared outside of an onClickListener before lifecycle state changes to started + ```kotlin + RoomBackup(this) + ``` - ```kotlin - RoomBackup(this) - ``` - - * Instance of your room database - + - Instance of your room database ```kotlin .database(*YourDatabase*.getInstance(this)) @@ -88,229 +83,226 @@ e.g. [`YourDatabase.kt`](app/src/main/java/de/raphaelebner/roomdatabasebackup/sa The following options are optional and the default options - * Enable logging, for debugging and some error messages +- Enable logging, for debugging and some error messages + ```kotlin + .enableLogDebug(false) + ``` - ```kotlin - .enableLogDebug(false) - ``` +- Set custom log tag - * Set custom log tag + ```kotlin + .customLogTag("debug_RoomBackup") + ``` +- Enable and set maxFileCount - ```kotlin - .customLogTag("debug_RoomBackup") - ``` + - if file count of Backups > maxFileCount all old / the oldest backup file will be deleted + - can be used with internal and external storage + - default: infinity - * Enable and set maxFileCount - * if file count of Backups > maxFileCount all old / the oldest backup file will be deleted - * can be used with internal and external storage - * default: infinity + ```kotlin + .maxFileCount(5) + ``` +- Encrypt your backup - ```kotlin - .maxFileCount(5) - ``` + - Is encrypted with AES encryption + - uses a random 15 digit long key with alphanumeric characters + - this key is saved in [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) + - backup name is default backup name + ".aes" - * Encrypt your backup - * Is encrypted with AES encryption - * uses a random 15 digit long key with alphanumeric characters - * this key is saved in [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) - * backup name is default backup name + ".aes" + ```kotlin + .backupIsEncrypted(false) + ``` +- Encrypt your backup with your own password / key - ```kotlin - .backupIsEncrypted(false) - ``` + - This property is only working, if `.backupIsEncrypted(true)` is set + - If you use the key to encrypt the backup, you will also need it to decrypt + - Example: If you want to create an encrypted backup, export it and import it to another device. Then you need a custom key, else the backup is encrypted with a random key, and you can not decrypt it on a new device - * Encrypt your backup with your own password / key - * This property is only working, if ```.backupIsEncrypted(true)``` is set - * If you use the key to encrypt the backup, you will also need it to decrypt - * Example: If you want to create an encrypted backup, export it and import it to another device. Then you need a custom key, else the backup is encrypted with a random key, and you can not decrypt it on a new device - - **Attention** - i do not assume any liability for the loss of your key + **Attention** + i do not assume any liability for the loss of your key - - ```kotlin - .customEncryptPassword("YOUR_SECRET_PASSWORD") - ``` + ```kotlin + .customEncryptPassword("YOUR_SECRET_PASSWORD") + ``` - * Save your backup to different storage - * External - * storage path: /storage/emulated/0/Android/data/*package*/files/backup/ - * This files will be deleted, if you uninstall your app - * ```RoomBackup.BACKUP_FILE_LOCATION_EXTERNAL``` - * Internal - * Private, storage not accessible - * This files will be deleted, if you uninstall your app - * ```RoomBackup.BACKUP_FILE_LOCATION_INTERNAL``` - * Custom Dialog (beta) - * You can choose to save or restore where ever you want. A CreateDocument() or OpenDocument() Activity will be launched where you can choose the location - * If your backup is encrypted I reccomend you using a custom encrption password else you can't restore your backup - * ```RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG``` - * Custom File (beta) - * You can choose to save or restore to/from a custom File. - * If your backup is encrypted I reccomend you using a custom encrption password else you can't restore your backup - * Please use ```backupLocationCustomFile(File)``` to set a custom File - * ```RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_FILE``` - - **Attention** - For custom dialog and custom file I only verified the functionality for local storage. For thirt party storage please try and contact me if it is not working. I hope I can find a solution and fix it :) - - - ```kotlin - .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) - ``` +- Save your backup to different storage - * Set a custom File to save/restore to/from - Only working if ```backupLocation``` is set to ```BACKUP_FILE_LOCATION_CUSTOM_FILE``` - You have to define a File withe Filename and extension + - External + - storage path: /storage/emulated/0/Android/data/_package_/files/backup/ + - This files will be deleted, if you uninstall your app + - `RoomBackup.BACKUP_FILE_LOCATION_EXTERNAL` + - Internal + - Private, storage not accessible + - This files will be deleted, if you uninstall your app + - `RoomBackup.BACKUP_FILE_LOCATION_INTERNAL` + - Custom Dialog (beta) + - You can choose to save or restore where ever you want. A CreateDocument() or OpenDocument() Activity will be launched where you can choose the location + - If your backup is encrypted I reccomend you using a custom encrption password else you can't restore your backup \* `RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG` + - Custom File (beta) - ```kotlin - .backupLocationCustomFile(backupLocationCustomFile: File) - ``` + - You can choose to save or restore to/from a custom File. + - If your backup is encrypted I reccomend you using a custom encrption password else you can't restore your backup + - Please use `backupLocationCustomFile(File)` to set a custom File + - `RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_FILE` - * Set a custom dialog title, when showing list of available backups to restore (only for external or internal storage) + **Attention** + For custom dialog and custom file I only verified the functionality for local storage. For thirt party storage please try and contact me if it is not working. I hope I can find a solution and fix it :) + ```kotlin + .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) + ``` - ```kotlin - .customRestoreDialogTitle("Choose file to restore") - ``` +- Set a custom File to save/restore to/from + Only working if `backupLocation` is set to `BACKUP_FILE_LOCATION_CUSTOM_FILE` + You have to define a File withe Filename and extension - * Set your custom name to the Backup files + ```kotlin + .backupLocationCustomFile(backupLocationCustomFile: File) + ``` - **Attention**\ - If a backup file with the same name already exists, it will be replaced +- Set a custom dialog title, when showing list of available backups to restore (only for external or internal storage) + ```kotlin + .customRestoreDialogTitle("Choose file to restore") + ``` - ```kotlin - .customBackupFileName(*DatabaseName* + *currentTime* + ".sqlite3") - ``` +- Set your custom name to the Backup files - * Run some code, after backup / restore process is finished - * success: Boolean (If backup / restore was successful = true) - * message: String (message with simple hints, if backup / restore failed) + **Attention**\ + If a backup file with the same name already exists, it will be replaced - ```kotlin - .onCompleteListener { success, message, exitCode -> - } - ``` + ```kotlin + .customBackupFileName(*DatabaseName* + *currentTime* + ".sqlite3") + ``` - * Restart your Application. Can be implemented in the onCompleteListener, when "success == true" +- Run some code, after backup / restore process is finished - **Attention**\ - it does not always work reliably!\ - But you can use other methods.\ - Important is that all activities / fragments that are still open must be closed and reopened\ - Because the Database instance is a new one, and the old activities / fragments are trying to - work with the old instance + - success: Boolean (If backup / restore was successful = true) + - message: String (message with simple hints, if backup / restore failed) - ```kotlin - .restartApp(Intent(this@MainActivity, MainActivity::class.java)) - ``` + ```kotlin + .onCompleteListener { success, message, exitCode -> + } + ``` + +- Restart your Application. Can be implemented in the onCompleteListener, when "success == true" + + **Attention**\ + it does not always work reliably!\ + But you can use other methods.\ + Important is that all activities / fragments that are still open must be closed and reopened\ + Because the Database instance is a new one, and the old activities / fragments are trying to + work with the old instance + + ```kotlin + .restartApp(Intent(this@MainActivity, MainActivity::class.java)) + ``` ### Exit Codes Here are all exit codes for the onCompleteListener. -They can be calles using ```OnCompleteListener.$NAME$``` - -| Exit Code | Name | Description | -| --------- | :--------------------------------------------------- | ------------ | -| 0 | ```EXIT_CODE_SUCCESS``` | No error, action successful | -| 1 | ```EXIT_CODE_ERROR``` | Other Error | -| 2 | ```EXIT_CODE_ERROR_BACKUP_FILE_CHOOSER``` | Error while choosing backup to restore. Maybe no file selected | -| 3 | ```EXIT_CODE_ERROR_BACKUP_FILE_CREATOR``` | Error while choosing backup file to create. Maybe no file selected | -| 4 | ```EXIT_CODE_ERROR_BACKUP_LOCATION_FILE_MISSING``` | [BACKUP_FILE_LOCATION_CUSTOM_FILE] is set but [RoomBackup.backupLocationCustomFile] is not set | -| 5 | ```EXIT_CODE_ERROR_BACKUP_LOCATION_MISSING``` | [RoomBackup.backupLocation] is not set | -| 6 | ```EXIT_CODE_ERROR_BY_USER_CANCELED``` | Restore dialog for internal/external storage was canceled by user | -| 7 | ```EXIT_CODE_ERROR_DECRYPTION_ERROR``` | Cannot decrypt provided backup file | -| 8 | ```EXIT_CODE_ERROR_ENCRYPTION_ERROR``` | Cannot encrypt database backup | -| 9 | ```EXIT_CODE_ERROR_RESTORE_BACKUP_IS_ENCRYPTED``` | You tried to restore a encrypted backup but [RoomBackup.backupIsEncrypted] is set to false | -| 10 | ```EXIT_CODE_ERROR_RESTORE_NO_BACKUPS_AVAILABLE``` | No backups to restore are available in internal/external sotrage | -| 11 | ```EXIT_CODE_ERROR_ROOM_DATABASE_MISSING``` | No room database to backup is provided | -| 12 | ```EXIT_CODE_ERROR_STORAGE_PERMISSONS_NOT_GRANTED``` | Storage permissions not granted for custom dialog | -| 13 | ```EXIT_CODE_ERROR_WRONG_DECRYPTION_PASSWORD``` | Cannot decrypt provided backup file because the password is incorrect | +They can be calles using `OnCompleteListener.$NAME$` + +| Exit Code | Name | Description | +| --------- | :----------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| 0 | `EXIT_CODE_SUCCESS` | No error, action successful | +| 1 | `EXIT_CODE_ERROR` | Other Error | +| 2 | `EXIT_CODE_ERROR_BACKUP_FILE_CHOOSER` | Error while choosing backup to restore. Maybe no file selected | +| 3 | `EXIT_CODE_ERROR_BACKUP_FILE_CREATOR` | Error while choosing backup file to create. Maybe no file selected | +| 4 | `EXIT_CODE_ERROR_BACKUP_LOCATION_FILE_MISSING` | [BACKUP_FILE_LOCATION_CUSTOM_FILE] is set but [RoomBackup.backupLocationCustomFile] is not set | +| 5 | `EXIT_CODE_ERROR_BACKUP_LOCATION_MISSING` | [RoomBackup.backupLocation] is not set | +| 6 | `EXIT_CODE_ERROR_BY_USER_CANCELED` | Restore dialog for internal/external storage was canceled by user | +| 7 | `EXIT_CODE_ERROR_DECRYPTION_ERROR` | Cannot decrypt provided backup file | +| 8 | `EXIT_CODE_ERROR_ENCRYPTION_ERROR` | Cannot encrypt database backup | +| 9 | `EXIT_CODE_ERROR_RESTORE_BACKUP_IS_ENCRYPTED` | You tried to restore a encrypted backup but [RoomBackup.backupIsEncrypted] is set to false | +| 10 | `EXIT_CODE_ERROR_RESTORE_NO_BACKUPS_AVAILABLE` | No backups to restore are available in internal/external sotrage | +| 11 | `EXIT_CODE_ERROR_ROOM_DATABASE_MISSING` | No room database to backup is provided | +| 12 | `EXIT_CODE_ERROR_STORAGE_PERMISSONS_NOT_GRANTED` | Storage permissions not granted for custom dialog | +| 13 | `EXIT_CODE_ERROR_WRONG_DECRYPTION_PASSWORD` | Cannot decrypt provided backup file because the password is incorrect | ### Example Activity (Kotlin and Java) #### Kotlin -* ##### Backup - - ```kotlin - val backup = RoomBackup(this) - ... - backup - .database(FruitDatabase.getInstance(this)) - .enableLogDebug(true) - .backupIsEncrypted(true) - .customEncryptPassword("YOUR_SECRET_PASSWORD") - .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) - .maxFileCount(5) - .apply { - onCompleteListener { success, message, exitCode -> - Log.d(TAG, "success: $success, message: $message, exitCode: $exitCode") - if (success) restartApp(Intent(this@MainActivity, MainActivity::class.java)) - } - } - .backup() - ``` - -* ##### Restore - - ```kotlin - val backup = RoomBackup(this) - ... - backup - .database(FruitDatabase.getInstance(this)) - .enableLogDebug(true) - .backupIsEncrypted(true) - .customEncryptPassword("YOUR_SECRET_PASSWORD") - .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) - .apply { - onCompleteListener { success, message, exitCode -> - Log.d(TAG, "success: $success, message: $message, exitCode: $exitCode") - if (success) restartApp(Intent(this@MainActivity, MainActivity::class.java)) - } - } - .restore() - ``` +- ##### Backup + + ```kotlin + val backup = RoomBackup(this) + ... + backup + .database(FruitDatabase.getInstance(this)) + .enableLogDebug(true) + .backupIsEncrypted(true) + .customEncryptPassword("YOUR_SECRET_PASSWORD") + .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) + .maxFileCount(5) + .apply { + onCompleteListener { success, message, exitCode -> + Log.d(TAG, "success: $success, message: $message, exitCode: $exitCode") + if (success) restartApp(Intent(this@MainActivity, MainActivity::class.java)) + } + } + .backup() + ``` + +- ##### Restore + + ```kotlin + val backup = RoomBackup(this) + ... + backup + .database(FruitDatabase.getInstance(this)) + .enableLogDebug(true) + .backupIsEncrypted(true) + .customEncryptPassword("YOUR_SECRET_PASSWORD") + .backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL) + .apply { + onCompleteListener { success, message, exitCode -> + Log.d(TAG, "success: $success, message: $message, exitCode: $exitCode") + if (success) restartApp(Intent(this@MainActivity, MainActivity::class.java)) + } + } + .restore() + ``` #### Java -* ##### Backup - - ```java - final RoomBackup roomBackup = new RoomBackup(MainActivityJava.this); - ... - roomBackup.database(FruitDatabase.Companion.getInstance(getApplicationContext())); - roomBackup.enableLogDebug(enableLog); - roomBackup.backupIsEncrypted(encryptBackup); - roomBackup.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL); - roomBackup.maxFileCount(5); - roomBackup.onCompleteListener((success, message, exitCode) -> { - Log.d(TAG, "success: " + success + ", message: " + message + ", exitCode: " + exitCode); - if (success) roomBackup.restartApp(new Intent(getApplicationContext(), MainActivityJava.class)); - }); - roomBackup.backup(); - ``` - -* ##### Restore - - ```java - final RoomBackup roomBackup = new RoomBackup(MainActivityJava.this); - ... - roomBackup.database(FruitDatabase.Companion.getInstance(getApplicationContext())); - roomBackup.enableLogDebug(enableLog); - roomBackup.backupIsEncrypted(encryptBackup); - roomBackup.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL); - roomBackup.onCompleteListener((success, message, exitCode) -> { - Log.d(TAG, "success: " + success + ", message: " + message + ", exitCode: " + exitCode); - if (success) roomBackup.restartApp(new Intent(getApplicationContext(), MainActivityJava.class)); - }); - roomBackup.restore(); - ``` +- ##### Backup + + ```java + final RoomBackup roomBackup = new RoomBackup(MainActivityJava.this); + ... + roomBackup.database(FruitDatabase.Companion.getInstance(getApplicationContext())); + roomBackup.enableLogDebug(enableLog); + roomBackup.backupIsEncrypted(encryptBackup); + roomBackup.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL); + roomBackup.maxFileCount(5); + roomBackup.onCompleteListener((success, message, exitCode) -> { + Log.d(TAG, "success: " + success + ", message: " + message + ", exitCode: " + exitCode); + if (success) roomBackup.restartApp(new Intent(getApplicationContext(), MainActivityJava.class)); + }); + roomBackup.backup(); + ``` + +- ##### Restore + + ```java + final RoomBackup roomBackup = new RoomBackup(MainActivityJava.this); + ... + roomBackup.database(FruitDatabase.Companion.getInstance(getApplicationContext())); + roomBackup.enableLogDebug(enableLog); + roomBackup.backupIsEncrypted(encryptBackup); + roomBackup.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL); + roomBackup.onCompleteListener((success, message, exitCode) -> { + Log.d(TAG, "success: " + success + ", message: " + message + ", exitCode: " + exitCode); + if (success) roomBackup.restartApp(new Intent(getApplicationContext(), MainActivityJava.class)); + }); + roomBackup.restore(); + ``` ### Example Fragment (Kotlin and Java) @@ -324,25 +316,19 @@ They can be calles using ```OnCompleteListener.$NAME$``` [`FragmentActivityJava.java`](app/src/main/java/de/raphaelebner/roomdatabasebackup/sample/FragmentActivityJava.java) [`MainFragmentJava.java`](app/src/main/java/de/raphaelebner/roomdatabasebackup/sample/MainFragmentJava.java) - -Sample app ----------- +## Sample app 1. Download this repo 2. Unzip 3. Android Studio --> File --> Open --> select this Project 4. within the app folder you find the sample app -Developed by ----------- - -* Raphael Ebner -* [paypal.me/raphaelebner](https://www.paypal.me/raphaelebner) - +## Developed by +- Raphael Ebner +- [paypal.me/raphaelebner](https://www.paypal.me/raphaelebner) -License ----------- +## License MIT License