diff --git a/README.md b/README.md index c33afb3..9cd2adb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Open Android Backup is a tiny shell script & Flutter app that makes securely bac The following data types can be automatically restored back to the device. -- Apps (.apk files of installed apps - app data not included - split APK support is experimental and can be found in the `split-apk-support` branch) +- Apps (app data not included due to system limitations) - Internal storage (pictures, downloads, videos, Signal backups if enabled, etc) - Contacts (exported in vCard format) @@ -33,11 +33,12 @@ These things are the majority of what most people would want to keep safe, but e - Works on the 3 major operating systems, and supports *any* modern Android device. - Wireless backups that allow you to normally use your phone while it's being backed up. - Backs up data not normally accessible through ADB using a native companion app. -- Tiny - the script is 5KB in size, and the companion app is around 15 megabytes. +- Tiny - the whole package is about 20 MB. - Doesn't use proprietary formats - your data is safe even if you can't run the script. Simply open archives created by this script using 7-Zip. - Backups are encrypted along with their metadata. - Optionally securely erases all unencrypted temporary files created by the script. -- All data is compressed using 7-Zip with maximum compression settings. +- All data is compressed using 7-Zip with configurable compression settings. + ## Installation ### Linux diff --git a/functions/backup_func.sh b/functions/backup_func.sh index 0b626e3..2dc4424 100644 --- a/functions/backup_func.sh +++ b/functions/backup_func.sh @@ -52,8 +52,8 @@ function backup_func() { ( apk_path=${app%=*} # apk path on device apk_path=${apk_path/package:} # strip "package:" - apk_clean_name=$(echo "$app" | awk -F "=" '{print $NF}' | tr -dc '[:alnum:].' | tr '[:upper:]' '[:lower:]') # package name - apk_base="$apk_clean_name-$RANDOM$RANDOM.apk" # apk filename in the backup archive + apk_clean_name=$(echo "$app" | awk -F "=" '{print $NF}' | tr -dc '[:alnum:]_.') # package name + #apk_base="$apk_clean_name-$RANDOM$RANDOM" # apk filename in the backup archive. Unused, removal pending? # e.g.: # app=package:/data/app/~~4wyPu0QoTM3AByZS==/org.fdroid.fdroid-iaTC9-W1lyR1FxO==/base.apk=org.fdroid.fdroid # apk_path=/data/app/~~4wyPu0QoTM3AByZS==/org.fdroid.fdroid-iaTC9-W1lyR1FxO==/base.apk @@ -62,8 +62,14 @@ function backup_func() { echo "Backing up app: $apk_clean_name ($apps_exported/$app_count)" - get_file "$(dirname "$apk_path")" "$(basename "$apk_path")" ./backup-tmp/Apps - mv "./backup-tmp/Apps/$(basename "$apk_path")" "./backup-tmp/Apps/$apk_base" || cecho "Couldn't find app $(basename "$apk_path") after exporting from device - ignoring." 1>&2 + # Get all the APKs associated with the package name, including split APKs + # TODO: Ensure the changes made to apk_clean_name don't break this under certain conditions + for apk in $(adb shell pm path "$apk_clean_name" | sed 's/package://g' | tr -d '\r'); do + # Create a directory for the app to store all the APKs + mkdir -p ./backup-tmp/Apps/"$apk_clean_name" + # Save the APK to its directory + get_file "$(dirname "$apk")" "$(basename "$apk")" ./backup-tmp/Apps/"$apk_clean_name" + done ) done diff --git a/functions/restore_func.sh b/functions/restore_func.sh index e733f6d..55b69af 100644 --- a/functions/restore_func.sh +++ b/functions/restore_func.sh @@ -48,15 +48,45 @@ function restore_func() { cecho "Restoring applications." # We don't want a single app to break the whole script set +e - # There's a 15 minute timeout for app installs just in case there is a - # misbehaving app blocking the whole restore process. - # Please note that this doesn't forcibly kill adb, rather it sends a simple SIGTERM signal. + # Apps containing their own directories may contain split APKs, which need to be installed using adb install-multiple. + # Those without directories were created by past versions of this script and need to be imported the traditional way. + + # Handle split APKs + # Find directories in the Apps directory + apk_dirs=$(find ./backup-tmp/Apps -mindepth 1 -maxdepth 1 -type d) + for apk_dir in $apk_dirs; do + # Install all APKs in the directory + # the APK files are sorted to ensure that base.apk is installed before split APKs + apk_files=$(find "$apk_dir" -type f -name "*.apk" | sort | tr '\n' ' ') + if [[ "$(uname -r | sed -n 's/.*\( *Microsoft *\).*/\1/ip')" ]]; then + cecho "Windows/WSL detected" + # shellcheck disable=SC2086 + timeout 900 ./windows-dependencies/adb/adb.exe install-multiple $apk_files + else + cecho "macOS/Linux detected" + # shellcheck disable=SC2086 + timeout 900 adb install-multiple $apk_files + fi + done + + # Now all that's left is ensuring backwards compatibility with old backups + # Look for APK files in the Apps directory + apk_files=$(find ./backup-tmp/Apps -maxdepth 1 -type f -name "*.apk" | sort) + # Notify if an old backup is being restored + if [ -n "$apk_files" ]; then + cecho "Old backup with no split APKs detected." + fi + # Install all APKs if [[ "$(uname -r | sed -n 's/.*\( *Microsoft *\).*/\1/ip')" ]]; then cecho "Windows/WSL detected" - find ./backup-tmp/Apps -type f -name "*.apk" -exec timeout 900 ./windows-dependencies/adb/adb.exe install {} \; + for apk_file in $apk_files; do + timeout 900 ./windows-dependencies/adb/adb.exe install "$apk_file" + done else cecho "macOS/Linux detected" - find ./backup-tmp/Apps -type f -name "*.apk" -exec timeout 900 adb install {} \; + for apk_file in $apk_files; do + timeout 900 adb install "$apk_file" + done fi set -e