Wie die anderen Male darf eine Antwort auf meine Frage keine App aus dem Play Store oder einer anderen Quelle in Betracht ziehen. Was ich suche, ist ein Tool, das in der Lage ist, Benutzer-Apps , System-Apps oder beide Kategorien zu sichern , wenn es von einem funktionierenden Android-Betriebssystem aus gestartet wird.
Eine Sicherung der externen Daten der Apps ist nicht relevant . Das einzige, was zählt, ist die Möglichkeit, die base.apk- Datei, die sich in jedem /data/app/appName/ -Verzeichnis befindet, im Stapelbetrieb zu sichern, damit ich sie entweder neu installieren kann, um zu einer früheren Version zurückzukehren, oder es von Grund auf neu zu installieren.
Schließlich wäre es mir lieber, wenn das Tool frei anpassbar wäre (z. B. nicht kompiliert). Vielleicht so etwas wie ein Shell-Skript?
Dieses Skript ist veraltet und wird nicht mehr unterstützt. Die neueste Version, die Android 5+ und Python 3.5+ erfordert und Arcus-Designvarianten und Substratum-Overlays unterstützt, finden Sie in meinem GitHub-Repository .
Hier ist mein überarbeitetes Skript, das jetzt als NEMRIS bezeichnet wird und die Frage beantwortet. Wie üblich ist es von jedem frei editierbar und auch sh-konform, was bedeutet, dass es von der Android-Shell ausgeführt werden kann.
Tatsächlich hängt das Skript vom aapt- Dienstprogramm ab, kann erkennen, ob das Dienstprogramm installiert ist, kann feststellen, ob die backupDir
und die appsToBackup
Variablen leer sind oder nicht, und wenn dies der Fall ist, setzt es Standardwerte, anstatt abzubrechen.
Dennoch kann die Datums -Binärdatei Ihre wahre Zeitzone nicht bestimmen, daher sollte jeder seine TZ
Variable manuell bearbeiten.
Sobald es zum ersten Mal ausgeführt wird, kann das Tool anhand eines mit MD5-Prüfsummen gefüllten Arrays erkennen, ob ein APK bereits gesichert wurde oder nicht.
Es speichert das Array auch in einem Wörterbuch namens md5sums.txt , das eine Klartextdatei ist, die sich im APK-Sicherungsverzeichnis befindet. Diese Funktion kann die verstrichene Zeit um gut die Hälfte reduzieren, hängt jedoch von einer Statistik- Binärdatei ab, die in der Lage ist, die genaue Größe einer Datei in Bytes zu messen. Wenn stat dem nicht entspricht, werden die Prüfsummen jedes Mal neu berechnet, wie in der vorherigen Version des Skripts. Damit soll sichergestellt werden, dass NEMRIS nur von aapt abhängig ist . Denken Sie daran, die md5sums.txt manuell zu löschen , wenn Sie den Sicherungsordner bereinigen.
Als Plus hat das Skript jetzt eine maxDictSize
Variable, die einen ganzzahligen Wert akzeptiert. Der eingegebene Wert wird als Bytes interpretiert. Dies kann angepasst werden und dient dazu, das Prüfsummenwörterbuch neu zu berechnen, wenn seine Größe das Maximum überschreitet.
Schließlich habe ich es gepatcht, um Apps von Drittanbietern zu unterstützen, deren Namen Schrägstriche enthalten. Keine seltsamen Fehler mehr, denke ich.
Ich hoffe, es kann sich als nützlich erweisen.
Lizenz: GNU General Public License, Version 3 oder höher.
#!/system/bin/sh
# nemris - an Android app backup tool
# Copyright (C) 2016 Death Mask Salesman
# <http://android.stackexchange.com/users/152843/death-mask-salesman>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License at <http://www.gnu.org/licenses/> for
# more details.
#This variable is used to calculate the total elapsed time
#DO NOT alter it, or the script won't be able to calculate it
SECONDS=0
#This variable is used to output the time when the script is launched
#Edit the plus/minus and the value after "UTC", to force date into displaying your correct time zone
timeAtStart="$(TZ=UTC-2 date +%H:%M:%S)"
#This variable stores the path where to backup your apps' APK files
#Edit it freely, but do not forget the quotes
backupDir=""
#This variable stores the path where the script is located
scriptDir="$(dirname "$(readlink -f "$0")")"
#This variable tells the script which apps to backup
#Supported values are:
# - "User": tells the script to backup only third-party apps
# - "System": tells the script to backup only system apps
# - "All": tells the script to backup both 3rd party and system apps
appsToBackup=""
#This variable contains the maximum size of the checksums dictionary, in bytes
#It is used to decide whether to flush the dictionary or not
typeset -i maxDictSize=20000
#This function outputs the time when the operations start. Purely cosmetic: can be disabled safely
#///Beginning of function "timeInfo"///
function timeInfo {
echo "[ INFO ] Operations started at "$timeAtStart"."
}
#///End of function "timeInfo"///
#This function checks if the "aapt" and "stat" utilities are installed
#///Beginning of function "dependencyChecker"///
function dependencyChecker {
echo "[ INFO ] Checking if aapt and stat are installed..."
whence -v aapt &> /dev/null
isAaptAbsent="$(echo $?)"
whence -v stat &> /dev/null
isStatAbsent="$(echo $?)"
if [ "$isAaptAbsent" == "0" ]; then
echo "[ INFO ] aapt has been found."
unset isAaptAbsent
else
echo "[ FATAL ] aapt cannot be found. Aborting."
exit
fi
if [ "$isStatAbsent" == "0" ]; then
echo "[ INFO ] stat has been found."
echo ""
echo "[ INFO ] Checking if stat can measure exact file sizes..."
stat -c %s "$scriptDir/nemris.sh" &> /dev/null
if [ "$(echo $?)" == "0" ]; then
echo "[ INFO ] Measurement successful."
isStatUsable="1"
unset isStatAbsent
else
echo "[ WARNING ] Measurement failed. stat will be ignored."
isStatUsable="0"
unset isStatAbsent
fi
else
echo "[ WARNING ] stat cannot be found."
isStatUsable="0"
unset isStatAbsent
fi
}
#///End of function "dependencyChecker"///
#This function verifies whether the values into "backupDir" and "appsToBackup" have anything inside or not
#In the case that the variables are empty, default values will be used, instead
#///Beginning of the function "variablesChecker"///
function variablesChecker {
echo "[ INFO ] Checking if a backup path has already been specified..."
if [ "$backupDir" == "$(cat /dev/null)" ]; then
echo "[ WARNING ] A backup path has not been specified."
echo "[ WARNING ] Setting the path to default (/sdcard/AppsBackup)."
backupDir="/sdcard/AppsBackup"
else
echo "[ INFO ] Backup path has already been specified."
fi
echo ""
echo "[ INFO ] Checking if the typology of apps to backup has already been chosen..."
if [ "$appsToBackup" == "$(cat /dev/null)" ]; then
echo "[ WARNING ] A typology of apps to backup has not been specified."
echo "[ WARNING ] Setting the default typology (User)."
appsToBackup="User"
else
echo "[ INFO ] A typology of apps has already been specified."
fi
}
#///End of the function "variablesChecker"///
#This function emulates the case insensitivity for "appsToBackup", usually provided by brace expansion, but lacked by sh
#In the case that an unsupported value is found, a default value will be used instead
#///Beginning of the function "caseInsensitiveWorkaround"///
function caseInsensitiveWorkaround {
systemArray="$(echo -n {s,S}{y,Y}{s,S}{t,T}{e,E}{m,M})"
userArray="$(echo -n {u,U}{s,S}{e,E}{r,R})"
allArray="$(echo -n {a,A}{l,L}{l,L})"
case ${appsToBackup:0:1} in
s|S)
for i in $systemArray; do
case "$appsToBackup" in
$i)
appsToBackup="System"
;;
esac
done
;;
u|U)
for i in $userArray; do
case "$appsToBackup" in
$i)
appsToBackup="User"
;;
esac
done
;;
a|A)
for i in $allArray; do
case "$appsToBackup" in
$i)
appsToBackup="All"
;;
esac
done
;;
*)
echo "[ WARNING ] \""$appsToBackup"\": invalid typology."
echo "[ WARNING ] Setting the default typology (User)."
appsToBackup="User"
;;
esac
case "$appsToBackup" in
System|User|All)
;;
*)
echo "[ WARNING ] \""$appsToBackup"\": invalid typology."
echo "[ WARNING ] Setting the default typology (User)."
appsToBackup="User"
;;
esac
}
#///End of the function "caseInsensitiveWorkaround"///
#This function checks if the backup directory already exists
#///Beginning of the function "backupDirCheck"///
function backupDirCheck {
echo "[ INFO ] Checking if the backup directory already exists..."
if [ -d "$backupDir" ]; then
echo -n "[ INFO ] Backup directory already exists, "
cd "$backupDir"
#echo "[ INFO ] Checking if the directory is empty..."
if [ "$(ls | grep "\.apk$" | head -n 1)" == "$(cat /dev/null)" ]; then
echo "and does not have any APK file inside."
else
echo "and has at least an APK file inside."
isDirectoryEmpty="0"
fi
else
echo "[ INFO ] Backup directory does not exist. Creating it now."
mkdir -p "$backupDir"
cd "$backupDir"
fi
}
#///End of the function "backupDirCheck"///
#This function compares the size of the checksums dictionary and flushes it if too big
#///Beginning of function "sizeComparer"///
function sizeComparer {
echo "[ INFO ] Comparing the dictionary size to the max value..."
typeset -i dictSize="$(stat -c %s "$backupDir/md5sums.txt")"
if [ $dictSize -ge maxDictSize ]; then
echo "[ INFO ] The dictionary size exceeds the maximum value. The checksums will be recomputed."
dictTooBig="1"
unset dictSize
else
echo "[ INFO ] The dictionary size does not exceed the maximum value."
fi
}
#///End of function "sizeComparer"///
#This function generates a MD5 array, filled with the checksum of each APK file
#///Beginning of the function "checksumsGenerator"///
function checksumsGenerator {
echo "[ INFO ] Generating file checksums..."
apkList="$(printf "%s\n" * | grep "\.apk$")"
for i in $apkList; do
tempMd5=($(md5sum $i))
md5Array="$tempMd5 $md5Array"
done
cat << EOF > "$backupDir/md5sums.txt"
md5Array="$md5Array"
EOF
echo "[ INFO ] MD5 array generated."
}
#///End of the function "checksumsGenerator"///
#This function creates a list of the apps to backup, based on the content in "appsToBackup"
#///Beginning of the function "appListGenerator"///
function appListGenerator {
case "$appsToBackup" in
System)
echo "[ INFO ] Retrieving system apps list..."
appList="$(pm list packages -s)"
;;
User)
echo "[ INFO ] Retrieving third-party apps list..."
appList="$(pm list packages -3)"
;;
All)
echo "[ INFO ] Retrieving apps list..."
appList="$(pm list packages)"
;;
esac
echo "[ INFO ] Applications list retrieved."
}
#///End of the function "appListGenerator"///
#This function creates an array, filled with each app's full path
#///Beginning of the function "apkPathRetriever"///
function apkPathRetriever {
echo "[ INFO ] Collecting the path of each app's APK..."
for i in $appList; do
apkPath="${i#p*:}"
apkPath="$(pm path $apkPath)"
apkPath="${apkPath#p*:}"
pathArray="$apkPath $pathArray"
done
echo "[ INFO ] Paths collected."
}
#///End of the function "apkPathRetriever"///
#This function extracts the label or the package name for the APK supplied to it
#It extracts the app label for any third-party app, the package name for any system app
#///Beginning of the function "appNameRetriever"///
function appNameRetriever {
case "$1" in
/system/*)
appName="${aaptOutput#*name=\'}"
appName="${appName//\'*/}"
displayedName="$appName"
;;
/data/*|/mnt/asec/*)
appName="${aaptOutput#*application-label:\'}"
appName="${appName//app*/}"
appName="${appName%\'*}"
displayedName=$appName
appName="${appName//\//}"
appName="$(printf "%s" $appName)"
;;
esac
}
#///End of the function "appNameRetriever"///
#This function retrieves the version number of the APK
#///Beginning of the function "appVersionRetriever"///
function appVersionRetriever {
appVersion="${aaptOutput#*versionName=\'}"
appVersion="${appVersion//platformBuildVersion*/}"
appVersion="${appVersion%\'*}"
appVersion="$(printf "%s" $appVersion)"
}
#///End of the function "appVersionRetriever"///
#This function compares the MD5 of the APK in question against any MD5 in the array
#If it finds a match, then the function exits and the APK isn't backed up
#///Beginning of the function "md5Compare"///
function md5Compare {
alreadyBackedUp=0
appMd5=($(md5sum "$1"))
for c in $md5Array; do
if [ "$alreadyBackedUp" == "0" ]; then
if [ "$appMd5" == "$c" ]; then
alreadyBackedUp=1;
fi
else
break;
fi
done
}
#///End of the function "md5Compare"///
#This function decides whether to backup an app or not
#It calls both "appNameRetriever" and "appVersionRetriever" for renaming any copied "base.apk"
#It also decides whether to call "md5Compare" or not, in order to see if an app has already been backed up
#///Beginning of the function "apkBackup"///
function apkBackup {
for i in $pathArray; do
aaptOutput="$(aapt d badging "$i")"
appNameRetriever "$i"
appVersionRetriever
if [ "$isDirectoryEmpty" == "0" ]; then
md5Compare "$i"
if [ "$alreadyBackedUp" == "0" ]; then
echo -n "[ INFO ] Backing up "$displayedName"... "
cp "$i" "$backupDir"/$appName"_"$appVersion.apk
echo "done."
md5Array="$appMd5 $md5Array"
else
echo "[ INFO ] "$displayedName" has already been backed up."
fi
else
echo -n "[ INFO ] Backing up "$displayedName"... "
cp "$i" "$backupDir"/$appName"_"$appVersion.apk
echo "done."
fi
done
if [ "$md5Array" != "$(cat /dev/null)" ]; then
cat << EOF > "$backupDir/md5sums.txt"
md5Array="$md5Array"
EOF
fi
}
#///End of the function "apkBackup"///
#This is the core of the tool
echo "**************************"
echo " NEMRIS - App backup tool "
echo " by Death Mask Salesman "
echo "**************************"
timeInfo
echo ""
dependencyChecker
echo ""
variablesChecker
echo ""
caseInsensitiveWorkaround
echo ""
backupDirCheck
echo ""
#This section checks whether to analyze the dictionary size
#It also decides whether to compute the checksums
if [ "$isDirectoryEmpty" == "0" ]; then
if [ -e "$backupDir/md5sums.txt" ]; then
if [ "$isStatUsable" == "1" ]; then
sizeComparer
echo ""
else
dictTooBig="1"
fi
if [ "$dictTooBig" == "1" ]; then
checksumsGenerator
echo ""
else
source "$backupDir/md5sums.txt"
fi
else
echo "[ INFO ] Checksums not calculated yet."
checksumsGenerator
echo ""
fi
fi
appListGenerator
echo ""
apkPathRetriever
echo ""
apkBackup
echo ""
echo "[ INFO ] Operations took "$(((SECONDS/60)/60))" hours, "$(((SECONDS/60)%60))" minutes and "$((SECONDS%60))" seconds."
echo "[ INFO ] All done!"
Dies ist eine spezielle, verbesserte Version des Standard -Nemris- Tools. Es stellt eine separate Antwort dar, da es zwar eine dramatische Geschwindigkeitsverbesserung bietet, aber größtenteils ungetestet ist (es funktioniert mit Sicherheit unter CM12.1 und CM13 ).
Dieses Tool ist unter der WTFPL-Lizenz lizenziert. Mit anderen Worten, machen Sie damit, was Sie wollen. Verwenden Sie seine Komponenten wieder, vergeben Sie Unterlizenzen ... und zitieren Sie mich als ursprünglichen Autor, wenn Sie möchten. Ich übernehme jedoch keine Verantwortung.
Um ein benutzerdefiniertes Sicherungsverzeichnis anzugeben, bearbeiten Sie Zeile 17 manuell . Wenn Sie es leer lassen, verwendet das Skript standardmäßig /sdcard/NemrisBackup .
Nemris kann entweder ohne Argumente oder mit zwei optionalen Argumenten gestartet werden. Verwendung:
nemris.sh [app_typology] [reset]
. Das erste Argument kann User , System , Disabled oder All sein oder auch leer gelassen werden. Wenn das angegebene Argument nicht erkannt oder null ist, verwendet das Tool standardmäßig User . Groß-/Kleinschreibung wird unterstützt.
Das zweite Argument darf nur zurückgesetzt werden und darf nur angegeben werden, wenn auch das erste Argument angegeben wurde. Wenn Sie dies tun, löscht das Tool seine Konfigurationsdateien, die sich am selben Ort wie das Skript befinden, und erstellt sie neu.
#!/system/bin/sh
# A bunch of variables and a function that facilitate the script's workings
# Do not alter them unless you know what you're doing
SECONDS=0
app_typology="$1"
null="$(cat /dev/null)"
script_location="$(dirname "$(readlink -f "$0")")"
function var_to_file {
echo "$1=\"$2\"" >> "$script_location/nemris_config.txt"
}
####################
# This variable is needed to define the backup location
backup_location=""
####################
# This function cleans up the files generated in a previous execution
function settings_md5_files_delete {
echo -ne "[ INFO ] Deleting Nemris configuration and MD5 dictionary..."
if [ -e "$script_location/nemris_config.txt" ]; then
if [ -e "$script_location/md5_dictionary.txt" ]; then
rm "$script_location/nemris_config.txt" "$script_location/md5_dictionary.txt"
else
rm "$script_location/nemris_config.txt"
fi
else
if [ -e "$script_location/md5_dictionary.txt" ]; then
rm "$script_location/md5_dictionary.txt"
else
echo -ne " no files to remove..."
fi
fi
echo " done. The files will be regenerated."
}
# This function checks if a settings file has been generated from a previous execution and loads its data
function settings_file_check {
echo -ne "[ INFO ] Checking for Nemris configuration file..."
if [ -e "$script_location/nemris_config.txt" ]; then
echo " found."
if [ "$backup_location" == "$null" ]; then
source "$script_location/nemris_config.txt"
else
temp="$backup_location"
source "$script_location/nemris_config.txt"
backup_location="$temp"
unset temp
fi
else
echo " not found. The configuration will be regenerated."
touch "$script_location/nemris_config.txt"
fi
}
# This function reads the list of the packages and generates a special dictionary
# This is the reason of the time gain between the legacy Nemris and this version
function packages_file_write {
echo -ne "[ INFO ] Generating refined packages list..."
if [ -e "$script_location/packages.txt" ]; then
echo -n "$null" > "$script_location/packages.txt"
fi
cat "/data/system/packages.xml" | grep "package name" > "$script_location/packages.txt"
IFS=$'\n'
packages="$(cat "$script_location/packages.txt")"
echo -n "$null" > "$script_location/packages.txt"
for i in $packages; do
package_name="${i//*package name=\"/}"
package_name="${package_name//\"*/}"
package_path="${i//*codePath=\"/}"
package_path="${package_path//\"*/}"
if [ "$(echo -ne "$package_path" | grep "\.apk$")" == "$null" ]; then
package_path="$package_path/$(ls "$package_path" | grep "\.apk$")"
fi
echo "$package_name:$package_path" >> "$script_location/packages.txt"
done
unset IFS package package_name package_path
echo " done."
}
# This function checks if aapt is installed
function aapt_check {
echo -ne "[ INFO ] Checking for aapt..."
whence -v aapt &> /dev/null
is_aapt_missing="$(echo $?)"
var_to_file "is_aapt_missing" "$is_aapt_missing"
echo " done."
}
# This function sets the backup location and the app typology to backup to default
function variables_default {
case $1 in
0)
echo -ne "[ INFO ] Setting backup directory and app typology to default..."
backup_location="/sdcard/NemrisBackup"
app_typology="User"
var_to_file "backup_location" "$backup_location"
echo " done."
;;
1)
echo -ne "[ INFO ] Setting backup location to default..."
backup_location="/sdcard/NemrisBackup"
var_to_file "backup_location" "$backup_location"
echo " done."
;;
2)
echo -ne "[ INFO ] Setting app typology to default..."
app_typology="User"
echo " done."
;;
esac
}
# This function ensures case insensitivity and saves a headache to the user
function app_typology_sanitize {
case ${app_typology:0:1} in
s|S)
if [ "$system_permutations" == "$null" ]; then
permutations_already_calculated=0
system_permutations="$(echo -n {s,S}{y,Y}{s,S}{t,T}{e,E}{m,M})"
fi
for i in $system_permutations; do
if [ "$app_typology" == "$i" ]; then
app_typology="System"
break
fi
done
if [ "$permutations_already_calculated" == "0" ]; then
var_to_file "system_permutations" "$system_permutations"
fi
;;
u|U)
if [ "$user_permutations" == "$null" ]; then
permutations_already_calculated=0
user_permutations="$(echo -n {u,U}{s,S}{e,E}{r,R})"
fi
for i in $user_permutations; do
if [ "$app_typology" == "$i" ]; then
app_typology="User"
break
fi
done
if [ "$permutations_already_calculated" == "0" ]; then
var_to_file "user_permutations" "$user_permutations"
fi
;;
d|D)
if [ "$disabled_permutations" == "$null" ]; then
permutations_already_calculated=0
disabled_permutations="$(echo -n {d,D}{i,I}{s,S}{a,A}{b,B}{l,L}{e,E}{d,D})"
fi
for i in $disabled_permutations; do
if [ "$app_typology" == "$i" ]; then
app_typology="Disabled"
break
fi
done
if [ "$permutations_already_calculated" == "0" ]; then
var_to_file "disabled_permutations" "$disabled_permutations"
fi
;;
a|A)
if [ "$all_permutations" == "$null" ]; then
permutations_already_calculated=0
all_permutations="$(echo -n {a,A}{l,L}{l,L})"
fi
for i in $all_permutations; do
if [ "$app_typology" == "$i" ]; then
app_typology="All"
break
fi
done
if [ "$permutations_already_calculated" == "0" ]; then
var_to_file "all_permutations" "$all_permutations"
fi
;;
System|User|Disabled|All)
;;
*)
echo -ne "[ WARN ] \"$app_typology\": invalid value. Setting to default (User)..."
app_typology="User"
echo " done."
;;
esac
case $app_typology in
System|User|Disabled|All)
;;
*)
echo -ne "[ WARN ] \"$app_typology\": invalid value. Setting to default (User)..."
app_typology="User"
echo " done."
;;
esac
}
# This function checks if the backup directory contains any APK
function backup_location_check {
if [ -d "$backup_location" ]; then
if [ "$(ls "$backup_location" | grep "\.apk$")" == "$null" ]; then
backup_directory_is_empty=1
else
backup_directory_is_empty=0
fi
else
echo -ne "[ INFO ] Creating backup directory..."
mkdir -p "$backup_location"
echo " done."
fi
cd "$backup_location"
}
# This function generates a MD5 checksums dictionary
# This shortens down the operations time in any execution of the script
function md5_dict_generate {
echo -ne "[ INFO ] Generating MD5 checksums..."
apk_list="$(printf "%s\n" * | grep "\.apk$")"
for i in $apk_list; do
temp=($(md5sum "$i"))
md5_array="$temp $md5_array"
done
echo -n "md5_array=\""$md5_array"\"" > "$script_location/md5_dictionary.txt"
echo " done."
}
# This function retrieves the list of installed apps
function apps_list_retrieve {
case $app_typology in
System)
echo -ne "[ INFO ] Retrieving system apps list..."
for i in $(pm list packages -s); do
pkg="${i//p*:/}"
pkg="${pkg//./\\.}"
apps_list="$apps_list $pkg"
done
echo " done."
;;
User)
echo -ne "[ INFO ] Retrieving third-party apps list..."
for i in $(pm list packages -3); do
pkg="${i//p*:/}"
pkg="${pkg//./\\.}"
apps_list="$apps_list $pkg"
done
echo " done."
;;
Disabled)
echo -ne "[ INFO ] Retrieving disabled apps list..."
for i in $(pm list packages -d); do
pkg="${i//p*:/}"
pkg="${pkg//./\\.}"
apps_list="$apps_list $pkg"
done
echo " done."
;;
All)
echo -ne "[ INFO ] Retrieving apps list..."
for i in $(pm list packages); do
pkg="${i//p*:/}"
pkg="${pkg//./\\.}"
apps_list="$apps_list $pkg"
done
echo " done."
;;
esac
}
# This function retrieves the APKs paths via their package name (from the dictionary)
# Actually, this is the second part of the magic
function apks_paths_retrieve {
echo -ne "[ INFO ] Collecting the path of each app's APK..."
for i in $apps_list; do
row="$(cat "$script_location/packages.txt" | grep "$i:")"
paths_list="$paths_list ${row//*:/}"
done
echo " done."
}
# This function retrieves the app name
# If an app has no name, it falls back to the package name
function app_name_retrieve {
app_name="$(echo -ne "$aapt_output" | grep "application-label:\'")"
if [ "$app_name" != "$null" ]; then
app_name="${app_name//application-label:\'/}"
app_name="${app_name%\'*}"
displayed_name="$app_name"
app_name="${app_name//\//}"
app_name="$(printf "%s" $app_name)"
else
app_name="$(echo -ne "$aapt_output" | grep "package: name.")"
app_name="${app_name//package: name=\'/}"
app_name="${app_name//\'*/}"
displayed_name="$app_name"
fi
}
# This function retrieves the app version
# If an app has no version (weird, but that happens) it defaults to "None"
function app_version_retrieve {
app_version="${aapt_output#*versionName=\'}"
app_version="${app_version//platformBuildVersion*/}"
app_version="${app_version%\'*}"
app_version="$(printf "%s" $app_version)"
if [ "$app_version" == "$null" ]; then
app_version="None"
fi
}
# This function sets the app name to the name of the APK file
# It's used when the app to be backed up is a system app, which may make aapt go crazy
function system_app_name_set {
app_name="$(basename $1)"
app_name="${app_name%\.apk}"
displayed_name="$app_name"
}
# This function checks if the checksum of any app figures in the already backed up apps
# This way, any app is backed up exactly once, and Nemris cannot be fooled by file names
function md5_compare {
already_backed_up=0
app_md5=($(md5sum "$1"))
for c in $md5_array; do
if [ "$already_backed_up" == "0" ]; then
if [ "$app_md5" == "$c" ]; then
already_backed_up=1
fi
else
break
fi
done
}
# This function backs up the APK files, and calls the appropriate functions to handle both system and third-party apps
function apk_backup {
for i in $paths_list; do
case $i in
/system/*)
system_app_name_set $i
;;
/data/app/*|/mnt/asec/*)
aapt_output="$(aapt d badging "$i")"
app_name_retrieve
app_version_retrieve
;;
esac
if [ "$backup_directory_is_empty" == "0" ]; then
md5_compare "$i"
if [ "$already_backed_up" == "0" ]; then
echo -ne "[ INFO ] Backing up "$displayed_name"..."
case $i in
/system/*)
cp "$i" "$backup_location"/$app_name.apk
;;
/data/app/*|/mnt/asec/*)
cp "$i" "$backup_location"/$app_name"_"$app_version.apk
;;
esac
md5_array="$app_md5 $md5_array"
echo " done."
else
echo "[ INFO ] "$displayed_name" has already been backed up."
fi
else
echo -ne "[ INFO ] Backing up "$displayed_name"..."
case $i in
/system/*)
cp "$i" "$backup_location"/$app_name.apk
;;
/data/app/*|/mnt/asec/*)
cp "$i" "$backup_location"/$app_name"_"$app_version.apk
;;
esac
echo " done."
fi
done
if [ "$md5_array" != "$null" ]; then
echo -ne "md5_array=\""$md5_array"\"" > "$script_location/md5_dictionary.txt"
fi
}
# This function informs about the time that has been required by all of the operations
function goodbye {
echo "[ INFO ] Operations took "$(((SECONDS/60)/60))" hours, "$(((SECONDS/60)%60))" minutes and "$((SECONDS%60))" seconds."
echo "[ INFO ] All done!"
}
####################
# This is the core of the tool
echo "**************************"
echo " NEMRIS - App backup tool "
echo " by Death Mask Salesman "
echo "**************************"
echo ""
# Logic that handles the optional second argument that may be supplied by an user
# Only the "reset" argument is detected
if [ "$2" == "reset" ]; then
settings_md5_files_delete
else
settings_file_check
fi
packages_file_write
if [ "$is_aapt_missing" == "$null" ]; then
aapt_check
fi
# Logic that aborts the execution if aapt is not present
if [ "$is_aapt_missing" == "1" ]; then
echo "[ FATAL ] aapt is not installed: aborting."
exit
fi
# Logic that decides whether variables to check
if [ "$backup_location" == "$null" ]; then
if [ "$app_typology" == "$null" ]; then
variables_default 0
else
variables_default 1
app_typology_sanitize
fi
else
if [ "$app_typology" == "$null" ]; then
variables_default 2
else
app_typology_sanitize
fi
fi
backup_location_check
# Logic that checks whether to compute the checksums of the already backed up apps
if [ "$backup_directory_is_empty" == "0" ]; then
if [ ! -e "$script_location/md5_dictionary.txt" ]; then
md5_dict_generate
else
source "$script_location/md5_dictionary.txt"
fi
fi
apps_list_retrieve
apks_paths_retrieve
echo ""
apk_backup
echo ""
goodbye
Izzy
adb backup
– also keine einfachen.apk
Dateien entweder (obwohl das hinzugefügt werden könnte, Wurzel gegeben).unvergesslichidUnterstütztMonica
Zauberbuch
unvergesslichidUnterstütztMonica