diff --git a/README_TS.md b/README_TS.md new file mode 100644 index 0000000..6a5602f --- /dev/null +++ b/README_TS.md @@ -0,0 +1,99 @@ +# backup_script 數據備份腳本 + ![主圖](https://github.com/Petit-Abba/backup_script_zh-CN/blob/06e06a015a1f672be52d980cb77ec0fd8dc4087d/File/mmexport1631297554615.png) + [![Stars](https://img.shields.io/github/stars/YAWAsau/backup_script?label=stars)](https://github.com/YAWAsau) + [![Download](https://img.shields.io/github/downloads/YAWAsau/backup_script/total)](https://github.com/YAWAsau/backup_script/releases) + [![Release](https://img.shields.io/github/v/release/YAWAsau/backup_script?label=release)](https://github.com/YAWAsau/backup_script/releases/latest) + [![License](https://img.shields.io/github/license/YAWAsau/backup_script?label=License)](https://choosealicense.com/licenses/gpl-3.0) + +
+ 簡體中文 | 繁體中文 +
+ + ## 概述 + 創作該腳本是為了使用戶能夠更加完整地**備份/恢復**軟件數據。 + + (&) 由於本人習慣輸入繁體中文,所以發布的版本為繁體版,如果需要**簡體版**,可前往這裡下載。 + > 簡體中文版:[backup_script_zh-CN](https://github.com/Petit-Abba/backup_script_zh-CN) + + ## 優勢 + - 數據完整:在更換系統之後,原有的數據全部保留,無需重新登陸或者下載額外數據包。 + - 速度快:目前支持的壓縮算法有 `tar(默認)` `lz4` `zstd` + - 易操作:下面簡單4步即可備份App完整數據! + + ## 如何使用 + `請認真閱讀以下說明,以減少不必要的問題。 ` + + **推薦工具**: [MT管理器](https://www.coolapk.com/apk/bin.mt.plus) + 警告! termux請勿使用tsu 支援設備必須安卓版本Android 8+ Arm64, + + > 1. __生成應用列表.sh__:將zip解壓縮到任意目錄,點擊`生成應用列表.sh`並勾選root執行腳本 [[示意圖]](https://github.com/Petit-Abba/backup_script_zh-CN//raw/main/File/Picture/1.png),等待提示結束 [[示意圖]](https://github.com/Petit-Abba/backup_script_zh-CN//raw/main/File/Picture/2.png)。 + + > 2. __應用列表.txt__:當前目錄下會生成一個`應用列表.txt`,這就是你**要備份的軟件列表**,你可以把**不需要備份的軟件那一行前加上`#`** [[示意圖]](https://github.com/Petit-Abba/backup_script_zh-CN//raw/main/File/Picture/3.png),備份時就會跳過它;如果你只需要備份一兩個軟件,那麼你可以**全選刪除**,然後按照這個格式:`[App名稱 App包名]` 進行填寫需要備份的軟件 [[示意圖]](https://github.com/Petit-Abba/backup_script_zh-CN//raw/main/File/Picture/4.png),這樣就不用一個一個去加`#`了。 + + > 3. __備份應用.sh__:以上簡單兩步你就設置好了需要備份的軟件,接下來點擊`備份應用.sh`並勾選root執行,等待備份結束 [[示意圖]](https://github.com/Petit-Abba/backup_script_zh-CN//raw/main/File/Picture/5.png)。 + + > 4. __備份完成__:完成後會在當前目錄生成一個Backup資料夾,裡面是你的軟件備份,把這個資料夾整個備份起來,刷完機直接在裡面找到`還原備份.sh`即可恢復備份的所有數據,同樣道理裡面有個應用列表.txt ,一樣跟第二步驟操作一樣不需要還原的刪除。 + + ##### 附加說明[1]:backup_settings.conf (備份設置) + ``` + 1=是 0=否 + + # 是否在每次執行備份腳本使用音量鍵詢問如下備份需求 + Lo=0 (如果是1,那下面三項設置就被忽略,改為音量鍵選擇。) + + # 選擇是否只備份split apk(分割apk檔,1備份split apk 0混合備份) + Splist=0 + + # 是否備份使用者數據 (1備份0不備份) + Backup_user_data=1 + + # 是否備份外部數據 即比如原神的數據包(1備份0不備份) + Backup_obb_data=0 + + # 備份路徑位置為絕對位置或是當前環境位置(1環境位置 0腳本所在位置) + path=0 + + # 壓縮算法(可用lz4 zstd tar tar為僅打包 有什麼好用的壓縮算法請聯繫我 + # lz4壓縮最快,但是壓縮率略差 zstd擁有良好的壓縮率與速度 當然慢於lz4 + Compression_method=zstd + ``` + `如果上面內容看不懂或者懶得看,你也可以選擇忽略,直接用默認即可。 ` + + + ##### 附加說明[2]:安裝Magisk模塊進行自動備份.sh (8.8.9版本更新加入) + ``` + 1. 刷入模塊 重啟 + + 2. 相關路徑查看:/storage/emulated/0/Android/backup_script/ + + 3. Magisk模塊會生成卡刷包,並且每隔4小時監控第三方軟件數量進行卡刷包生成服務,防止突然不能開機時丟失軟件數據。 + + 4. 生成的卡刷包必須進入recovery才能刷入進行備份。 + ``` + + ## 關於反饋 + - 如果使用過程中出現問題,請攜帶截圖並詳細說明問題建立[issues](https://github.com/YAWAsau/backup_script/issues)。 + - 酷安@[落葉淒涼TEL](http://www.coolapk.com/u/2277637) + + ## 常見問題 + ``` + Q:批量備份大量提示失敗怎麼辦? + A:退出腳本,刪除/data/backup_tools,再備份一次。 + + Q:批量恢復大量提示失敗怎麼辦? + A:退出腳本,按照上面同樣操作。 如果還是錯誤,請建立issues,我幫你排除錯誤。 + + Q:微信/QQ 能不能完美備份&恢復數據? + A:不能保證,有的人說不能有的人說能,所以備份會有提示。 建議用你信賴的備份軟件針對微信/QQ再備份一次,以防丟失重要數據。 + + Q:為什麼部分APP備份很久? 比如王者榮耀、PUBG、原神、微信、QQ。 + A:因為連同軟件數據包都給你備份了,原神數據包9GB+當然久到裂開了,恢復同理,還要解壓縮數據包。 + ``` + + ## 銘謝貢獻 + - 臭批老k([kmou424](https://github.com/kmou424)):提供部分與驗證函數思路 + - 屑老方([雄氏老方](http://www.coolapk.com/u/665894)):提供自動更新腳本方案 + - 依心所言&情非得已c:提供appinfo替代aapt作為更高效的dump包名 + - 胖子老陳(雨季騷年) + + `文檔編輯:Petit-Abba` \ No newline at end of file diff --git a/backup_settings.conf b/backup_settings.conf new file mode 100644 index 0000000..f0d2544 --- /dev/null +++ b/backup_settings.conf @@ -0,0 +1,34 @@ +#1開啟0關閉 +#是否在每次執行備份腳本使用音量鍵詢問如下備份需求 +#如果是那下面三項設置就被忽略,改為音量鍵選擇 +Lo=0 + +#備份路徑位置為絕對位置或是當前環境位置(1環境位置 0腳本所在位置) +path=0 + +#選擇是否只備份split apk(分割apk檔,1備份split apk 0混合備份) +Splist=0 + +#是否備份使用者數據 (1備份0不備份) +Backup_user_data=1 + +#是否備份外部數據 即比如原神的數據包(1備份0不備份) +Backup_obb_data=0 + +#是否在應用數據備份好後備份自定義目錄 +backup_media=0 + +#單獨生成可在recovery中用於救急備份的卡刷,並且跳過應用備份? +Hybrid_backup=0 + +#添加自定義備份路徑 請勿刪除" " +Custom_path=" +/storage/emulated/0/Pictures +/storage/emulated/0/Download +/storage/emulated/0/Music +/storage/emulated/0/DCIM +" + +#壓縮算法(可用lz4 zstd tar tar為僅打包 有什麼好用的壓縮算法請聯繫我 +#lz4壓縮最快,但是壓縮率略差 zstd擁有良好的壓縮率與速度 當然慢於lz4 +Compression_method=zstd \ No newline at end of file diff --git a/tools/META-INF/com/google/android/update-binary b/tools/META-INF/com/google/android/update-binary new file mode 100644 index 0000000..6879ef3 --- /dev/null +++ b/tools/META-INF/com/google/android/update-binary @@ -0,0 +1,243 @@ +#!/sbin/sh +#初始化 +OUTFD="$2" +ZIPFILE="$3" + +#设置字符输出 +ui_print() { + echo "ui_print "$@"" > /proc/self/fd/$OUTFD +} +#设置工作目录 +MODDIR=/dev/backup +#安装二进制文件 +rm -rf "$MODDIR" +mkdir -p "$MODDIR" +unzip -o "$ZIPFILE" 'apk/Message.apk' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/pv' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/bin.sh' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/busybox' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/appinfo' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/appinfo.dex' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/tar' -d "$MODDIR" +unzip -o "$ZIPFILE" 'bin/zstd' -d "$MODDIR" +unzip -o "$ZIPFILE" 'script/restore' -d "$MODDIR" +unzip -o "$ZIPFILE" 'script/restore2' -d "$MODDIR" +unzip -o "$ZIPFILE" 'script/Get_DirName' -d "$MODDIR" +unzip -o "$ZIPFILE" 'script/應用列表.txt' -d "$MODDIR" +unzip -o "$ZIPFILE" 'script/backup_settings.conf' -d "$MODDIR" +chmod -R 0755 "$MODDIR/bin/" +busybox="$MODDIR/bin/busybox" +mkdir -p "$MODDIR/xbin" +"$busybox" --list | while read; do + case $REPLY in + tar) ;; + *) + ln -s "$busybox" "$MODDIR/xbin/$REPLY" + ;; + esac +done +isBoolean() { + nsx="$1" + if [[ $1 = 1 ]];then + nsx=true + elif [[ $1 = 0 ]];then + nsx=false + else + ui_print "script/backup_settings.conf填寫錯誤" && exit 2 + fi +} +Set_back() { + return 1 +} +#设置环境 +export PATH="$MODDIR/xbin:$MODDIR/bin:$PATH" +. "$MODDIR/script/backup_settings.conf" +i=1 +txt="$MODDIR/script/應用列表.txt" +isBoolean "$Splist" && Splist="$nsx" +isBoolean "$Backup_obb_data" && Backup_obb_data="$nsx" +isBoolean "$Backup_user_data" && Backup_user_data="$nsx" +[[ ! -f $txt ]] && ui_print "$txt缺少" && exit 1 +r="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n '$=')" +[[ $r = "" ]] && ui_print "爬..應用列表.txt是空的備份個鬼" && exit 0 +path="/data/media/0/Android" +path2="/data/data" +data="/data" +ui_print $(df -h "$data") +ui_print $(df -h "$data" | awk 'END{print "剩餘:"$3"使用率:"$4}') +Backup="/data/media/0/TWRP/Backup_$Compression_method" +[[ ! -d $Backup ]] && mkdir -p "$Backup" || rm -rf "$Backup"/* +[[ ! -f $Backup/應用列表.txt ]] && echo "#不需要恢復還原的應用請在開頭注釋# 比如#xxxxxxxx 酷安" >"$Backup/應用列表.txt" +[[ ! -d $Backup/bin ]] && cp -r "$MODDIR/bin" "$Backup" && cp -r "$MODDIR/apk" "$Backup/bin" +[[ ! -f $Backup/還原備份.sh ]] && cp -r "$MODDIR/script/restore" "$Backup/還原備份.sh" +[[ ! -f $Backup/掃描資料夾名.sh ]] && cp -r "$MODDIR/script/Get_DirName" "$Backup/掃描資料夾名.sh" +filesize="$(du -ks "$Backup" | awk '{print $1}')" +#調用二進制 +Quantity=0 +#顯示執行結果 +echo_log() { + if [[ $? = 0 ]]; then + ui_print "$1成功" && result=0 + else + ui_print "$1備份失敗,過世了" && result=1 + fi +} +#檢測apk狀態進行備份 +Backup_apk() { + #創建APP備份文件夾 + [[ ! -d $Backup_folder ]] && mkdir -p "$Backup_folder" + #備份apk + ui_print "$1" + [[ $lxj -ge 95 ]] && ui_print "$data空間不足,達到$lxj%" && exit 2 + rm -rf "$Backup_folder"/*.apk + [[ $(cat "$Backup/應用列表.txt" | grep -v "#" | sed -e '/^$/d' | awk '{print $2}' | grep -w "^${name}$" | head -1) = "" ]] && echo "$name2 $name" >>"$Backup/應用列表.txt" + find "$apk_path" -maxdepth 1 -name "*.apk" -type f | while read; do + path="$REPLY" + b_size="$(ls -l "$path" | awk '{print $5}')" + k_size="$(awk 'BEGIN{printf "%.2f\n", "'$b_size'"/'1024'}')" + m_size="$(awk 'BEGIN{printf "%.2f\n", "'$k_size'"/'1024'}')" + ui_print "${path##*/} ${m_size}MB(${k_size}KB)" + done + (cd "$apk_path" + case $Compression_method in + tar|TAR|Tar) tar -cf "$Backup_folder/apk.tar" *.apk ;; + zstd|Zstd|ZSTD) tar -cf - *.apk | zstd -r -T0 -6 -q >"$Backup_folder/apk.tar.zst" ;; + esac) + echo_log "備份$apk_number個Apk" + if [[ $result = 0 ]]; then + [[ $PackageName = "" ]] && echo "PackageName=\"$name\"" >>"$app_details" + [[ $ChineseName = "" ]] && echo "ChineseName=\"$name2\"" >>"$app_details" + [[ ! -f $Backup_folder/還原備份.sh ]] && cp -r "$MODDIR/script/restore2" "$Backup_folder/還原備份.sh" + fi + if [[ $name = com.android.chrome ]]; then + #刪除所有舊apk ,保留一個最新apk進行備份 + ReservedNum=1 + FileNum="$(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | wc -l)" + while [[ $FileNum -gt $ReservedNum ]]; do + OldFile="$(ls -rt /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | head -1)" + ui_print "刪除文件:${OldFile%/*/*}" + rm -rf "${OldFile%/*/*}" + let "FileNum--" + done + [[ -f $(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null) && $(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | wc -l) = 1 ]] && cp -r "$(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null)" "$Backup_folder/nmsl.apk" + fi + [[ $name = bin.mt.plus && -f $apk_path/base.apk && ! -f $Backup/$name2.apk ]] && cp -r "$apk_path/base.apk" "$Backup/$name2.apk" + unset PackageName ChineseName ; D=1 +} +#檢測數據位置進行備份 +Backup_data() { + unset zsize + case $1 in + user) data_path="$path2/$name" ;; + data) data_path="$path/$1/$name" ;; + obb) data_path="$path/$1/$name" ;; + *) [[ -f $app_details ]] && data_path="$2" && Compression_method=tar && zsize=1 ;; + esac + if [[ -d $data_path ]]; then + [[ $lxj -ge 95 ]] && ui_print "$data空間不足,達到$lxj%" && exit 2 + ui_print "備份$1數據" + case $1 in + user) + case $Compression_method in + tar|Tar|TAR) tar --exclude="${data_path##*/}/.ota" --exclude="${data_path##*/}/cache" --exclude="${data_path##*/}/lib" -cpf "$Backup_folder/$1.tar" -C "${data_path%/*}" "${data_path##*/}" 2>/dev/null ;; + zstd|Zstd|ZSTD) tar --exclude="${data_path##*/}/.ota" --exclude="${data_path##*/}/cache" --exclude="${data_path##*/}/lib" -cpf - -C "${data_path%/*}" "${data_path##*/}" 2>/dev/null | zstd -r -T0 -6 -q >"$Backup_folder/$1.tar.zst" ;; + *) ui_print "$Compression_method為不支持的壓縮算法" && rm -rf "$Backup" && exit 2 ;; + esac ;; + *) + case $Compression_method in + tar|Tar|TAR) tar --exclude="Backup_"* -cPpf "$Backup_folder/$1.tar" "$data_path" 2>/dev/null ;; + zstd|Zstd|ZSTD) tar --exclude="Backup_"* -cPpf - "$data_path" 2>/dev/null | zstd -r -T0 -6 -q >"$Backup_folder/$1.tar.zst" ;; + *) ui_print "$Compression_method為不支持的壓縮算法" && rm -rf "$Backup" && exit 2 ;; + esac ;; + esac + echo_log "備份$1數據" + else + ui_print "$1數據不存在跳過備份" + fi +} +endtime() { + #計算總體切換時長耗費 + case $1 in + 1) starttime="$starttime1" ;; + 2) starttime="$starttime2" ;; + esac + endtime="$(date -u "+%s")" + duration="$(echo "$((endtime - starttime))" | awk '{t=split("60 秒 60 分 24 時 999 天",a);for(n=1;n/dev/null | wc -l)" + if [[ $apk_number = 1 ]]; then + if [[ $Splist = false ]]; then + Backup_apk "非Split Apk" + else + ui_print "非Split Apk跳過備份" + unset D + fi + else + Backup_apk "Split Apk支持備份" + fi + if [[ $D != "" && $result = 0 && $No_backupdata = "" ]]; then + if [[ $Backup_obb_data = true ]]; then + #備份data數據 + Backup_data "data" + #備份obb數據 + Backup_data "obb" + fi + #備份user數據 + [[ $Backup_user_data = true ]] && Backup_data "user" + fi + endtime 2 "$name2備份" + ui_print "完成$((i*100/r))% $hx$(df -h "$data" | awk 'END{print "剩餘:"$3"使用率:"$4}')" + else + ui_print "$name2[$name]不在安裝列表,備份個寂寞?" + fi + ui_print " + " + let i++ +done +#計算出備份大小跟差異性 +filesizee="$(du -ks "$Backup" | awk '{print $1}')" +dsize="$(($((filesizee - filesize)) / 1024))" +ui_print "備份資料夾路徑:$Backup" +ui_print "備份資料夾總體大小$(du -ksh "$Backup" | awk '{print $1}')" +if [[ $dsize -gt 0 ]]; then + if [[ $((dsize / 1024)) -gt 0 ]]; then + ui_print "本次備份: $((dsize / 1024))gb" + else + ui_print "本次備份: ${dsize}mb" + fi +else + ui_print "本次備份: $(($((filesizee - filesize)) * 1000 / 1024))kb" +fi +ui_print "批量備份完成" +endtime 1 "批量備份開始到結束" +rm -rf "$MODDIR" +exit 0 +}& \ No newline at end of file diff --git a/tools/apk/Message.apk b/tools/apk/Message.apk new file mode 100644 index 0000000..0ff0025 Binary files /dev/null and b/tools/apk/Message.apk differ diff --git a/tools/bin/appinfo b/tools/bin/appinfo new file mode 100644 index 0000000..fa5ee19 --- /dev/null +++ b/tools/bin/appinfo @@ -0,0 +1,2 @@ +export CLASSPATH="${0%/*}/appinfo.dex" +exec app_process /system/bin --nice-name=appinfo indi.appinfo.AppInfo "$@" \ No newline at end of file diff --git a/tools/bin/appinfo.dex b/tools/bin/appinfo.dex new file mode 100644 index 0000000..3f892c9 Binary files /dev/null and b/tools/bin/appinfo.dex differ diff --git a/tools/bin/bin.sh b/tools/bin/bin.sh new file mode 100644 index 0000000..c2ca563 --- /dev/null +++ b/tools/bin/bin.sh @@ -0,0 +1,151 @@ +test "$(whoami)" != root && echo "你是憨批?不給Root用你媽 爬" && exit 1 +abi="$(getprop ro.product.cpu.abi)" +case $abi in +arm64*) + [[ $(getprop ro.build.version.sdk) -lt 28 ]] && echo "設備Android $(getprop ro.build.version.release)版本過低 請升級至Android 9+" && exit 1 + ;; +*) + echo "-未知的架構: $abi" + exit 1 + ;; +esac +#if [[ -d /data/user/0/com.tencent.mobileqq/files/aladdin_configs/964103426 ]]; then +# echo "爬 不給你用臭批阿巴" && exit 2 +#fi +if [[ -d $(magisk --path) ]]; then + PATH="/system_ext/bin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin:/data/data/Han.GJZS/files/usr/busybox:/data/data/Han.GJZS/files/usr/bin:$(magisk --path)/.magisk/busybox" +else + PATH="/system_ext/bin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin:/data/data/Han.GJZS/files/usr/busybox:/data/data/Han.GJZS/files/usr/bin" + echo "Magisk busybox Path does not exist" +fi ; export PATH="$PATH" +backup_version="V10.6 2021/10/22-20:59" +#設置二進制命令目錄位置 +[[ $bin_path = "" ]] && echo "未正確指定bin.sh位置" && exit 2 +bin_path="${bin_path/'/storage/emulated/'/'/data/media/'}" +MODDIR="${MODDIR/'/storage/emulated/'/'/data/media/'}" +Status_log="$MODDIR/執行狀態日誌.txt" +rm -rf "$Status_log" +filepath="/data/backup_tools" +busybox="$filepath/busybox" +busybox2="$bin_path/busybox" +#排除自身 +exclude=" +busybox_path +bin.sh" +if [[ ! -d $filepath ]]; then + mkdir -p "$filepath" + [[ $? = 0 ]] && echo "設置busybox環境中" +fi +[[ ! -f $bin_path/busybox_path ]] && touch "$bin_path/busybox_path" +if [[ $filepath != $(cat "$bin_path/busybox_path") ]]; then + [[ -d $(cat "$bin_path/busybox_path") ]] && rm -rf "$(cat "$bin_path/busybox_path")" + echo "$filepath">"$bin_path/busybox_path" +fi +#刪除無效軟連結 +find -L "$filepath" -maxdepth 1 -type l -exec rm -rf {} \; +if [[ -d $bin_path ]]; then + [[ ! -f $busybox2 ]] && echo "$busybox2不存在" && exit 1 + if [[ -f $busybox ]]; then + filemd5="$(md5sum "$busybox" | cut -d" " -f1)" + filemd5_1="$(md5sum "$busybox2" | cut -d" " -f1)" + if [[ $filemd5 != $filemd5_1 ]]; then + echo "busybox md5不一致 重新創立環境中" + rm -rf "$filepath"/* + fi + fi + find "$bin_path" -maxdepth 1 -type f | egrep -v "$(echo $exclude | sed 's/ /\|/g')" | while read; do + File_name="${REPLY##*/}" + if [[ ! -f $filepath/$File_name ]]; then + cp -r "$REPLY" "$filepath" + chmod 0777 "$filepath/$File_name" + echo "$File_name > $filepath/$File_name" + else + filemd5="$(md5sum "$filepath/$File_name" | cut -d" " -f1)" + filemd5_1="$(md5sum "$bin_path/$File_name" | cut -d" " -f1)" + if [[ $filemd5 != $filemd5_1 ]]; then + echo "$File_name md5不一致 重新創建" + cp -r "$REPLY" "$filepath" + chmod 0777 "$filepath/$File_name" + echo "$File_name > $filepath/$File_name" + fi + fi + done + "$busybox" --list | while read; do + if [[ $REPLY != tar && ! -f $filepath/$REPLY ]]; then + ln -fs "$busybox" "$filepath/$REPLY" + fi + done +else + echo "遺失$bin_path" + exit 1 +fi +if [[ ! -f $busybox ]]; then + echo "不存在$busybox ...." + exit 1 +fi +export PATH="$filepath:$PATH" +export TZ=Asia/Taipei +Open_apps="$(dumpsys window | grep -w mCurrentFocus | egrep -oh "[^ ]*/[^//}]+" | cut -f 1 -d "/")" +#下列為自定義函數 +Set_back() { + return 1 +} +endtime() { + #計算總體切換時長耗費 + case $1 in + 1) starttime="$starttime1" ;; + 2) starttime="$starttime2" ;; + esac + endtime="$(date -u "+%s")" + duration="$(echo $((endtime - starttime)) | awk '{t=split("60 秒 60 分 24 時 999 天",a);for(n=1;n>"$Status_log" +} +get_version() { + while :; do + version="$(getevent -qlc 1 | awk '{ print $3 }')" + case $version in + KEY_VOLUMEUP) + branch=true + echoRgb "$1" + ;; + KEY_VOLUMEDOWN) + branch=false + echoRgb "$2" + ;; + *) + continue + ;; + esac + sleep 1.2 + break + done +} +isBoolean() { + nsx="$1" + if [[ $1 = 1 ]];then + nsx=true + elif [[ $1 = 0 ]];then + nsx=false + else + echoRgb "$MODDIR/backup_settings.conf $1填寫錯誤" "0" && exit 2 + fi +} +bn=147 +echoRgb "\n --------------歡迎使用⚡️🤟🐂纸備份--------------\n -當前腳本執行路徑:$MODDIR\n -busybox版本:$(busybox | head -1 | awk '{print $2}')\n -appinfo版本:$(appinfo --version)\n -腳本版本:$backup_version\n -設備架構$abi\n -品牌:$(getprop ro.product.brand)\n -設備代號:$(getprop ro.product.device)\n -型號:$(getprop ro.product.model)\n -Android版本:$(getprop ro.build.version.release)\n -SDK:$(getprop ro.build.version.sdk)\n -終端:$( -o ands -pn "$Open_apps" 2>/dev/null)" +bn=195 \ No newline at end of file diff --git a/tools/bin/busybox b/tools/bin/busybox new file mode 100644 index 0000000..bfa27b6 Binary files /dev/null and b/tools/bin/busybox differ diff --git a/tools/bin/longToast b/tools/bin/longToast new file mode 100644 index 0000000..6ae6eb3 --- /dev/null +++ b/tools/bin/longToast @@ -0,0 +1,4 @@ +#!/system/bin/sh + +a=$(echo "$*" | sed 's#/#{xiegang}#g') +content query --uri content://ice.message/long/"$*" >/dev/null 2>&1 \ No newline at end of file diff --git a/tools/bin/lz4 b/tools/bin/lz4 new file mode 100644 index 0000000..bc69d14 Binary files /dev/null and b/tools/bin/lz4 differ diff --git a/tools/bin/notify b/tools/bin/notify new file mode 100644 index 0000000..f27f18e --- /dev/null +++ b/tools/bin/notify @@ -0,0 +1,10 @@ +#!/system/bin/sh + +a=$(echo "$2" | sed 's#/#{xiegang}#g') +b=$(echo "$3" | sed 's#/#{xiegang}#g') + +if [[ "$4" = "" ]]; then + content query --uri content://ice.message/notify/"$1<|>$a<|>$b<|>" >/dev/null 2>&1 +else + content query --uri content://ice.message/notify/"$1<|>$a<|>$b<|>$4" >/dev/null 2>&1 +fi \ No newline at end of file diff --git a/tools/bin/pv b/tools/bin/pv new file mode 100644 index 0000000..a609c32 Binary files /dev/null and b/tools/bin/pv differ diff --git a/tools/bin/tar b/tools/bin/tar new file mode 100644 index 0000000..cd95bd5 Binary files /dev/null and b/tools/bin/tar differ diff --git a/tools/bin/zip b/tools/bin/zip new file mode 100644 index 0000000..05407ae Binary files /dev/null and b/tools/bin/zip differ diff --git a/tools/bin/zstd b/tools/bin/zstd new file mode 100644 index 0000000..d396208 Binary files /dev/null and b/tools/bin/zstd differ diff --git a/tools/script/Get_DirName b/tools/script/Get_DirName new file mode 100644 index 0000000..d288a50 --- /dev/null +++ b/tools/script/Get_DirName @@ -0,0 +1,14 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +bin_path="$MODDIR/bin" +[[ ! -d $bin_path ]] && echo "$bin_path目錄遺失" && exit 1 +txt="$MODDIR/應用列表.txt" +. "$bin_path/bin.sh" +echo "#不需要恢復還原的應用請在開頭注釋# 比如#xxxxxxxx 酷安">"$txt" +find "$MODDIR" -maxdepth 1 -type d | sort | sed 's/\[/ /g ; s/\]//g' | while read; do + case ${REPLY##*/} in + 媒體|backup_*|Backup_*|bin) ;; + *) echo "${REPLY##*/}">>"$txt" ;; + esac +done +echoRgb "$txt重新生成" \ No newline at end of file diff --git a/tools/script/backup_settings.conf b/tools/script/backup_settings.conf new file mode 100644 index 0000000..eb41648 --- /dev/null +++ b/tools/script/backup_settings.conf @@ -0,0 +1,13 @@ +#1開啟0關閉 +#選擇是否只備份split apk(分割apk檔,1備份split apk 0混合備份) +Splist=0 + +#是否備份外部數據 即比如原神的數據包(1備份0不備份) +Backup_obb_data=1 + +#備份user數據 +Backup_user_data=1 + +#壓縮算法(可用zstd tar tar為僅打包 +#zstd擁有良好的壓縮率與速度 當然慢於tar +Compression_method=zstd \ No newline at end of file diff --git a/tools/script/restore b/tools/script/restore new file mode 100644 index 0000000..e5205e4 --- /dev/null +++ b/tools/script/restore @@ -0,0 +1,187 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +bin_path="$MODDIR/bin" +[[ ! -d $bin_path ]] && echo "$bin_path目錄遺失" && exit 1 +. "$bin_path/bin.sh" +path="/data/media/0/Android" +path2="/data/data" +TMPDIR="/data/local/tmp" +[[ ! -d $TMPDIR ]] && mkdir "$TMPDIR" +[[ ! -d $path2 ]] && echoRgb "設備不存在user目錄" "0" && exit 1 +[[ ! -d $bin_path/apk ]] && echo "$bin_path/apk目錄遺失" && exit 1 +i=1 +txt="$MODDIR/應用列表.txt" +[[ ! -f $txt ]] && echoRgb "請執行\"掃描資料夾名.sh\"獲取應用列表再來恢復" "0" && exit 2 +r="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n '$=')" +[[ $r = "" ]] && echoRgb "應用列表.txt包名為空或是被注釋了" "0" && exit 1 +if [[ $(pm path ice.message) = "" ]]; then + echoRgb "未安裝toast 開始安裝" "0" + cp -r "$bin_path/apk"/*.apk "$TMPDIR" && pm install --user 0 -r "$TMPDIR"/*.apk >/dev/null 2>&1 && rm -rf "$TMPDIR"/* + [[ $? = 0 ]] && echoRgb "安裝toast成功" "1" || echoRgb "安裝toast失敗" "0" +fi +#顯示執行結果 +echo_log() { + if [[ $? = 0 ]]; then + echoRgb "$1成功" "1" && result=0 + else + echoRgb "$1失敗,過世了" "0" && result=1 && let ERROR++ + fi +} +Release_data() { + tar_path="$1" + X="$path2/$name" + FILE_NAME="${tar_path##*/}" + FILE_NAME2="${FILE_NAME%%.*}" + echoRgb "恢復$FILE_NAME2數據" "2" + if [[ $FILE_NAME2 = user ]]; then + if [[ -d $X ]]; then + case ${FILE_NAME##*.} in + lz4) pv "$tar_path" | tar --recursive-unlink -I lz4 -xmpf - -C "$path2" ;; + zst) pv "$tar_path" | tar --recursive-unlink -I zstd -xmpf - -C "$path2" ;; + tar) pv "$tar_path" | tar --recursive-unlink -xmpf - -C "$path2" ;; + *) (echoRgb "$FILE_NAME 壓縮包不支持解壓縮" "0" ; Set_back) + esac + else + echoRgb "$X不存在 無法恢復$FILE_NAME2數據" "0" && Set_back + fi + else + case ${FILE_NAME##*.} in + lz4) pv "$tar_path" | tar --recursive-unlink -I lz4 -xmPpf - ;; + zst) pv "$tar_path" | tar --recursive-unlink -I zstd -xmPpf - ;; + tar) pv "$tar_path" | tar --recursive-unlink -xmPpf - ;; + *) (echoRgb "$FILE_NAME 壓縮包不支持解壓縮" "0" ; Set_back) + esac + fi + echo_log "$FILE_NAME 解壓縮($FILE_NAME2)" + if [[ $result = 0 ]]; then + if [[ $FILE_NAME2 = user ]]; then + if [[ -d $X ]]; then + if [[ -f /config/sdcardfs/$name/appid ]]; then + G="$(cat "/config/sdcardfs/$name/appid")" + else + G="$(dumpsys package "$name" | awk '/userId=/{print $1}' | cut -f2 -d '=' | head -1)" + fi ; G="$(echo "$G" | grep -Eo '[0-9]+')" + if [[ $G != "" ]]; then + echoRgb "路徑:$X" + Path_details="$(stat -c "%A/%a %U/%G" "$X")" + chown -hR "$G:$G" "$X" + echo_log "設置用戶組:$(echo "$Path_details" | awk '{print $2}')" + restorecon -R "$X" >/dev/null 2>&1 + echo_log "selinux上下文設置" + #echoRgb "$(stat -c "%n %A/%a %U/%G" "$X" | awk '{print "路徑:"$1"\n 權限:"$2"\n 用戶組:"$3}')" + else + echoRgb "uid獲取失敗" "0" + fi + else + echoRgb "路徑$X不存在" "0" + fi + elif [[ $FILE_NAME2 = data ]]; then + chown -R "1023:1078" "$path/data/$name" + fi + fi +} +#開始循環$txt內的資料進行恢複 +#記錄開始時間 +starttime1="$(date -u "+%s")" +TIME="$starttime1" +#記錄error次數起點 +ERROR=1 +{ +while [[ $i -le $r ]]; do + #let bn++ + #[[ $bn -ge 37 ]] && bn=31 + echoRgb "恢複第$i個應用 總共$r個 剩下$((r-i))個應用" + name="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n "${i}p" | awk '{print $2}')" + name2="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n "${i}p" | awk '{print $1}')" + Backup_folder="$MODDIR/${name2}[${name}]" + Backup_folder2="$MODDIR/媒體" + [[ $name = "" ]] && echoRgb "警告! 應用列表.txt應用包名獲取失敗,可能修改有問題" "0" && exit 1 + if [[ -d $Backup_folder ]]; then + echoRgb "恢複$name2 ($name)" + starttime2="$(date -u "+%s")" + if [[ $(pm path "$name") = "" ]]; then + apkfile="$(find "$Backup_folder" -maxdepth 1 -name "apk.*" -type f 2>/dev/null)" + if [[ $apkfile != "" ]]; then + rm -rf "$TMPDIR"/* + case ${apkfile##*.} in + lz4) pv "$apkfile" | tar -I lz4 -xmpf - -C "$TMPDIR" ;; + zst) pv "$apkfile" | tar -I zstd -xmpf - -C "$TMPDIR" ;; + tar) pv "$apkfile" | tar -xmpf - -C "$TMPDIR" ;; + *) (echoRgb "${apkfile##*/} 壓縮包不支持解壓縮" "0" ; Set_back) + esac + echo_log "${apkfile##*/}解壓縮" && [[ -f $Backup_folder/nmsl.apk ]] && cp -r "$Backup_folder/nmsl.apk" "$TMPDIR" + else + echoRgb "你的Apk壓縮包離家出走了,可能備份後移動過程遺失了\n -解決辦法手動安裝Apk後再執行恢復腳本" "0" + fi + if [[ $result = 0 ]]; then + case $(find "$TMPDIR" -maxdepth 1 -name "*.apk" -type f 2>/dev/null | wc -l) in + 1) + echoRgb "恢復普通apk" + pm install --user 0 -r "$TMPDIR"/*.apk >/dev/null 2>&1 + echo_log "Apk安裝" + ;; + 0) + echoRgb "$TMPDIR中沒有apk" "0" + ;; + *) + echoRgb "恢復split apk" + b="$(pm install-create --user 0 | grep -E -o '[0-9]+')" + if [[ -f $TMPDIR/nmsl.apk ]]; then + pm install --user 0 -r "$TMPDIR/nmsl.apk" >/dev/null 2>&1 + echo_log "nmsl.apk安裝" + fi + find "$TMPDIR" -maxdepth 1 -name "*.apk" -type f | grep -v 'nmsl.apk' | while read; do + pm install-write "$b" "${REPLY##*/}" "$REPLY" >/dev/null 2>&1 + echo_log "${REPLY##*/}安裝" + done + pm install-commit "$b" >/dev/null 2>&1 + echo_log "split Apk安裝" + ;; + esac + fi + else + echoRgb "存在當前系統中略過安裝Apk" + fi + if [[ $(pm path "$name") != "" ]]; then + #停止應用 + [[ $name != $Open_apps ]] && am force-stop "$name" + find "$Backup_folder" -maxdepth 1 ! -name "apk.*" -name "*.tar*" -type f | sort | while read; do + Release_data "$REPLY" + done + else + echoRgb "$name2沒有安裝無法恢復數據" "0" + fi + endtime 2 "恢複" && echoRgb "完成$((i*100/r))%" && echoRgb + else + echoRgb "$Backup_folder資料夾遺失,無法恢複" "0" + fi + if [[ $i = $r ]]; then + endtime 1 "應用恢復" + if [[ -d $Backup_folder2 ]]; then + echoRgb "是否恢復多媒體數據\n 音量上恢復,音量下不恢復" + get_version "恢復媒體數據" "跳過恢復媒體數據" + starttime1="$(date -u "+%s")" + A=1 + B="$(find "$Backup_folder2" -maxdepth 1 -name "*.tar*" -type f | wc -l)" + if [[ $branch = true ]]; then + find "$Backup_folder2" -maxdepth 1 -name "*.tar*" -type f | while read; do + echoRgb "恢復第$A個壓縮包 總共$B個 剩下$((B-A))個" + Release_data "$REPLY" + echoRgb "完成$((A*100/B))%" && let A++ + done + endtime 1 "自定義恢復" + fi + fi + fi + if [[ $ERROR -ge 5 ]]; then + echoRgb "錯誤次數達到上限 環境已重設" "0" && rm -rf "$filepath" + echoRgb "請重新執行腳本" "0" && exit + fi + let i++ +done +starttime1="$TIME" +echoRgb "批量恢複完成" && endtime 1 "批量恢複開始到結束" && echoRgb "應用閃退請重新開機" "0" +} & +wait +longToast "批量恢復完成" +Print "批量恢復完成 執行過程請查看$Status_log" && rm -rf "$TMPDIR"/* \ No newline at end of file diff --git a/tools/script/restore2 b/tools/script/restore2 new file mode 100644 index 0000000..88d9360 --- /dev/null +++ b/tools/script/restore2 @@ -0,0 +1,135 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +bin_path="${MODDIR%/*}/bin" +[[ ! -d $bin_path ]] && echo "$bin_path目錄遺失" && exit 1 +. "$bin_path/bin.sh" +path="/data/media/0/Android" +path2="/data/data" +TMPDIR="/data/local/tmp" +[[ ! -d $TMPDIR ]] && mkdir "$TMPDIR" +[[ ! -d $path2 ]] && echoRgb "設備不存在user目錄" "0" && exit 1 +#記錄開始時間 +starttime1="$(date -u "+%s")" +#顯示執行結果 +echo_log() { + if [[ $? = 0 ]]; then + echoRgb "$1成功" "1" && result=0 + else + echoRgb "$1失敗,過世了" "0" && result=1 + fi +} +{ +Backup_folder="$MODDIR" +if [[ ! -f $Backup_folder/app_details ]]; then + echoRgb "$Backup_folder/app_details遺失,無法獲取包名" "0" && exit 1 +else + . "$Backup_folder/app_details" +fi +name="$PackageName" ; [[ $name = "" ]] && echoRgb "包名獲取失敗" "0" && exit 2 +name2="$ChineseName" ; [[ $name2 = "" ]] && echoRgb "應用名獲取失敗" "0" && exit 2 +echoRgb "恢複$name2 ($name)" +starttime2="$(date -u "+%s")" +if [[ $(pm path "$name") = "" ]]; then + apkfile="$(find "$Backup_folder" -maxdepth 1 -name "apk.*" -type f 2>/dev/null)" + if [[ $apkfile != "" ]]; then + rm -rf "$TMPDIR"/* + case ${apkfile##*.} in + lz4) pv "$apkfile" | tar -I lz4 -xmpf - -C "$TMPDIR" ;; + zst) pv "$apkfile" | tar -I zstd -xmpf - -C "$TMPDIR" ;; + tar) pv "$apkfile" | tar -xmpf - -C "$TMPDIR" ;; + *) (echoRgb "${apkfile##*/} 壓縮包不支持解壓縮" "0" ; Set_back) + esac + echo_log "${apkfile##*/}解壓縮" && [[ -f $Backup_folder/nmsl.apk ]] && cp -r "$Backup_folder/nmsl.apk" "$TMPDIR" + else + echoRgb "你的Apk壓縮包離家出走了,可能備份後移動過程遺失了\n -解決辦法手動安裝Apk後再執行恢復腳本" "0" + fi + if [[ $result = 0 ]]; then + case $(find "$TMPDIR" -maxdepth 1 -name "*.apk" -type f 2>/dev/null | wc -l) in + 1) + echoRgb "恢復普通apk" + pm install --user 0 -r "$TMPDIR"/*.apk >/dev/null 2>&1 + echo_log "Apk安裝" + ;; + 0) + echoRgb "$TMPDIR中沒有apk" "0" + ;; + *) + echoRgb "恢復split apk" + b="$(pm install-create --user 0 | grep -Eo '[0-9]+')" + if [[ -f $TMPDIR/nmsl.apk ]]; then + pm install --user 0 -r "$TMPDIR/nmsl.apk" >/dev/null 2>&1 + echo_log "nmsl.apk安裝" + fi + find "$TMPDIR" -maxdepth 1 -name "*.apk" -type f | grep -v 'nmsl.apk' | while read; do + pm install-write "$b" "${REPLY##*/}" "$REPLY" >/dev/null 2>&1 + echo_log "${REPLY##*/}安裝" + done + pm install-commit "$b" >/dev/null 2>&1 + echo_log "split Apk安裝" + ;; + esac + fi +else + echoRgb "存在當前系統中略過安裝Apk" +fi +if [[ $(pm path "$name") != "" ]]; then + #停止應用 + [[ $name != $Open_apps ]] && am force-stop "$name" + find "$Backup_folder" -maxdepth 1 ! -name "apk.*" -name "*.tar*" -type f | sort | while read; do + tar_path="$REPLY" + X="$path2/$name" + FILE_NAME="${tar_path##*/}" + FILE_NAME2="${FILE_NAME%%.*}" + echoRgb "恢復$FILE_NAME2數據" "2" + if [[ $FILE_NAME2 = user ]]; then + if [[ -d $X ]]; then + case ${FILE_NAME##*.} in + lz4) pv "$tar_path" | tar --recursive-unlink -I lz4 -xmpf - -C "$path2" ;; + zst) pv "$tar_path" | tar --recursive-unlink -I zstd -xmpf - -C "$path2" ;; + tar) pv "$tar_path" | tar --recursive-unlink -xmpf - -C "$path2" ;; + *) (echoRgb "$FILE_NAME 壓縮包不支持解壓縮" "0" ; Set_back) + esac + else + (echoRgb "$X不存在 無法恢復$FILE_NAME2數據" "0" ; Set_back) + fi + else + case ${FILE_NAME##*.} in + lz4) pv "$tar_path" | tar --recursive-unlink -I lz4 -xmPpf - ;; + zst) pv "$tar_path" | tar --recursive-unlink -I zstd -xmPpf - ;; + tar) pv "$tar_path" | tar --recursive-unlink -xmPpf - ;; + *) (echoRgb "$FILE_NAME 壓縮包不支持解壓縮" "0" ; Set_back) + esac + fi + echo_log "$FILE_NAME 解壓縮($FILE_NAME2)" + if [[ $result = 0 ]]; then + if [[ $FILE_NAME2 = user ]]; then + if [[ -d $X ]]; then + if [[ -f /config/sdcardfs/$name/appid ]]; then + G="$(cat "/config/sdcardfs/$name/appid")" + else + G="$(dumpsys package "$name" | awk '/userId=/{print $1}' | cut -f2 -d '=' | head -1)" + fi ; G="$(echo "$G" | grep -Eo '[0-9]+')" + if [[ $G != "" ]]; then + echoRgb "路徑:$X" + Path_details="$(stat -c "%A/%a %U/%G" "$X")" + chown -hR "$G:$G" "$X" + echo_log "設置用戶組:$(echo "$Path_details" | awk '{print $2}')" + restorecon -R "$X" >/dev/null 2>&1 + echo_log "selinux上下文設置" + else + echoRgb "uid獲取失敗" "0" + fi + else + echoRgb "路徑$X不存在" "0" + fi + elif [[ $FILE_NAME2 = data ]]; then + chown -R "1023:1078" "$path/data/$name" + fi + fi + done +else + echoRgb "$name2沒有安裝無法恢復數據" "0" +fi +} & +wait +endtime 1 "恢複開始到結束" && echoRgb "應用閃退請重新開機" "0" && rm -rf "$TMPDIR"/* \ No newline at end of file diff --git a/tools/script/restore3 b/tools/script/restore3 new file mode 100644 index 0000000..d4aa7ea --- /dev/null +++ b/tools/script/restore3 @@ -0,0 +1,36 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +bin_path="${MODDIR%/*}/bin" +[[ ! -d $bin_path ]] && echo "$bin_path目錄遺失" && exit 1 +. "$bin_path/bin.sh" +#記錄開始時間 +starttime1="$(date -u "+%s")" +echo_log() { + if [[ $? = 0 ]]; then + echoRgb "$1成功" "1" && result=0 + else + echoRgb "$1恢複失敗,過世了" "0" && result=1 + fi +} +Release_data() { + tar_path="$1" + FILE_NAME="${tar_path##*/}" + FILE_NAME2="${FILE_NAME%%.*}" + echoRgb "恢復$FILE_NAME2數據" "2" && usertar="1" + case ${FILE_NAME##*.} in + lz4) pv "$1" | tar --recursive-unlink -I lz4 -xmPpf - ; Set_back ;; + zst) pv "$1" | tar --recursive-unlink -I zstd -xmPpf - ;; + tar) pv "$1" | tar --recursive-unlink -xmPpf - ;; + *) (echoRgb "$FILE_NAME 壓縮包不支持解壓縮" "0" ; Set_back) + esac + echo_log "$FILE_NAME 解壓縮($FILE_NAME2)" +} +starttime1="$(date -u "+%s")" +A=1 +B="$(find "$MODDIR" -maxdepth 1 -name "*.tar*" -type f | wc -l)" +find "$MODDIR" -maxdepth 1 -name "*.tar*" -type f | while read; do + echoRgb "恢復第$A個壓縮包 總共$B個 剩下$((B-A))個" + Release_data "$REPLY" + echoRgb "完成$((A*100/B))%" && let A++ +done +endtime 1 "恢複結束" \ No newline at end of file diff --git a/備份應用.sh b/備份應用.sh new file mode 100644 index 0000000..3b74e97 --- /dev/null +++ b/備份應用.sh @@ -0,0 +1,326 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +tools_path="$MODDIR/tools" +bin_path="$tools_path/bin" +script_path="$tools_path/script" +script="${0##*/}" +[[ $(echo "$MODDIR" | grep -v 'mt') = "" ]] && echo "我他媽骨灰給你揚了撒了TM不解壓縮?用毛線 憨批" && exit 1 +[[ ! -d $tools_path ]] && echo "$tools_path目錄遺失" && exit 1 +[[ ! -d $script_path ]] && echo "$script_path目錄遺失" && exit 1 +[[ ! -d $tools_path/META-INF ]] && echo "$tools_path/META-INF目錄遺失" && exit 1 +[[ ! -d $tools_path/apk ]] && echo "$tools_path/apk目錄遺失" && exit 1 +. "$bin_path/bin.sh" +. "$MODDIR/backup_settings.conf" +case $MODDIR in +/storage/emulated/0/Android/*|/data/media/0/Android/*|/sdcard/Android/*) echoRgb "請勿在$MODDIR內備份" "0" && exit 2 ;; +esac +case $Compression_method in +zstd|Zstd|ZSTD|tar|Tar|TAR|lz4|Lz4|LZ4) ;; +*) echoRgb "$Compression_method為不支持的壓縮算法" "0" && exit 2 ;; +esac +[[ ! -f $MODDIR/backup_settings.conf ]] && echoRgb "backup_settings.conf遺失" "0" && exit 1 +if [[ $(pgrep -f "$script" | grep -v grep | wc -l) -ge 2 ]]; then + echoRgb "檢測到進程殘留,請重新執行腳本 已銷毀進程" "0" + pgrep -f "$script" | grep -v grep | while read i; do + [[ $i != "" ]] && kill -9 " $i" >/dev/null + done +fi +#效驗選填是否正確 +isBoolean "$Lo" && Lo="$nsx" +if [[ $Lo = false ]]; then + isBoolean "$Splist" && Splist="$nsx" + isBoolean "$Backup_obb_data" && Backup_obb_data="$nsx" + isBoolean "$path" && path3="$nsx" + isBoolean "$Backup_user_data" && Backup_user_data="$nsx" + isBoolean "$backup_media" && backup_media="$nsx" + isBoolean "$Hybrid_backup" && Hybrid_backup="$nsx" +else + echoRgb "備份路徑位置為絕對位置或是當前環境位置\n 音量上當前環境位置,音量下腳本絕對位置" + get_version "當前環境位置" "腳本絕對位置" && path3="$branch" +fi +i=1 +#數據目錄 +path="/data/media/0/Android" +path2="/data/user/0" +TMPDIR="/data/local/tmp" +[[ ! -d $TMPDIR ]] && mkdir "$TMPDIR" +if [[ $path3 = true ]]; then + Backup="$PWD/Backup_$Compression_method" + txt="$PWD/應用列表.txt" +else + Backup="$MODDIR/Backup_$Compression_method" + txt="$MODDIR/應用列表.txt" +fi +PU="$(ls /dev/block/vold | grep public)" +[[ ! -f $txt ]] && echoRgb "請執行\"生成應用列表.sh\"獲取應用列表再來備份" "0" && exit 1 +r="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n '$=')" +[[ $r = "" ]] && echoRgb "爬..應用列表.txt是空的或是包名被注釋了這樣備份個鬼" "0" && exit 1 +data=/data +hx="本地" +if [[ $(pm path ice.message) = "" ]]; then + echoRgb "未安裝toast 開始安裝" "0" + cp -r "$tools_path/apk"/*.apk "$TMPDIR" && pm install --user 0 -r "$TMPDIR"/*.apk &>/dev/null && rm -rf "$TMPDIR"/* + [[ $? = 0 ]] && echoRgb "安裝toast成功" "1" || echoRgb "安裝toast失敗" "0" +fi +echoRgb "-壓縮方式:$Compression_method" +echoRgb "-提示 腳本支持後台壓縮 可以直接離開腳本\n -或是關閉終端也能備份 如需終止腳本\n -請再次執行$script即可停止\n -備份結束將發送toast提示語" "2" +if [[ $PU != "" ]]; then + [[ -f /proc/mounts ]] && PT="$(cat /proc/mounts | grep "$PU" | awk '{print $2}')" + if [[ -d $PT ]]; then + echoRgb "檢測到usb 是否在usb備份\n 音量上是,音量下不是" + get_version "USB備份" "本地備份" + if $branch = true ]]; then + Backup="$PT/Backup_$Compression_method" + data="/dev/block/vold/$PU" + hx="USB" + fi + fi +else + echoRgb "沒有檢測到USB於本地備份" "2" +fi +[[ $Backup_user_data = false ]] && echoRgb "當前backup_settings.conf的\n -Backup_user_data為0將不備份user數據" "0" +[[ $Backup_obb_data = false ]] && echoRgb "當前backup_settings.conf的\n -Backup_obb_data為0將不備份外部數據" "0" +[[ $Hybrid_backup = true ]] && echoRgb "當前backup_settings.conf的\n -Hybrid_backup為1將不備份任何應用" "0" +[[ ! -d $Backup ]] && mkdir -p "$Backup" +[[ ! -f $Backup/應用列表.txt ]] && echo "#不需要恢復還原的應用請在開頭注釋# 比如#xxxxxxxx 酷安" >"$Backup/應用列表.txt" +[[ ! -d $Backup/tools ]] && cp -r "$bin_path" "$Backup" && cp -r "$tools_path/apk" "$Backup/bin" && rm -rf "$Backup/bin/toast" "$Backup/bin/zip" +[[ ! -f $Backup/還原備份.sh ]] && cp -r "$script_path/restore" "$Backup/還原備份.sh" +[[ ! -f $Backup/掃描資料夾名.sh ]] && cp -r "$script_path/Get_DirName" "$Backup/掃描資料夾名.sh" +filesize="$(du -ks "$Backup" | awk '{print $1}')" +#調用二進制 +Quantity=0 +#顯示執行結果 +echo_log() { + if [[ $? = 0 ]]; then + echoRgb "$1成功" "1" && result=0 + else + echoRgb "$1失敗,過世了" "0" && result=1 && let ERROR++ + fi +} +#檢測apk狀態進行備份 +Backup_apk() { + #創建APP備份文件夾 + [[ ! -d $Backup_folder ]] && mkdir -p "$Backup_folder" + [[ $(cat "$Backup/應用列表.txt" | grep -v "#" | sed -e '/^$/d' | awk '{print $2}' | grep -w "^${name}$" | head -1) = "" ]] && echo "$name2 $name" >>"$Backup/應用列表.txt" + if [[ $apk_version = $(dumpsys package "$name" | awk '/versionName=/{print $1}' | cut -f2 -d '=' | head -1) ]]; then + unset xb ; result=0 + echoRgb "Apk版本無更新 跳過備份" + else + [[ $lxj -ge 95 ]] && echoRgb "$data空間不足,達到$lxj%" "0" && exit 2 + rm -rf "$Backup_folder"/*.apk + #備份apk + echoRgb "$1" + [[ $name != $Open_apps ]] && am force-stop "$name" + echo "$apk_path" | sed -e '/^$/d' | while read; do + path="$REPLY" + b_size="$(ls -l "$path" | awk '{print $5}')" + k_size="$(awk 'BEGIN{printf "%.2f\n", "'$b_size'"/'1024'}')" + m_size="$(awk 'BEGIN{printf "%.2f\n", "'$k_size'"/'1024'}')" + echoRgb "${path##*/} ${m_size}MB(${k_size}KB)" "2" + done + (cd "$apk_path2" + case $Compression_method in + tar|TAR|Tar) tar -cf "$Backup_folder/apk.tar" *.apk ;; + lz4|LZ4|Lz4) tar -cf - *.apk | lz4 -1 >"$Backup_folder/apk.tar.lz4" ;; + zstd|Zstd|ZSTD) tar -cf - *apk | zstd -r -T0 -6 -q >"$Backup_folder/apk.tar.zst" ;; + esac) + echo_log "備份$apk_number個Apk" + if [[ $result = 0 ]]; then + echo "apk_version=\"$(dumpsys package "$name" | awk '/versionName=/{print $1}' | cut -f2 -d '=' | head -1)\"" >>"$app_details" + [[ $PackageName = "" ]] && echo "PackageName=\"$name\"" >>"$app_details" + [[ $ChineseName = "" ]] && echo "ChineseName=\"$name2\"" >>"$app_details" + [[ ! -f $Backup_folder/還原備份.sh ]] && cp -r "$script_path/restore2" "$Backup_folder/還原備份.sh" + fi + if [[ $name = com.android.chrome ]]; then + #刪除所有舊apk ,保留一個最新apk進行備份 + ReservedNum=1 + FileNum="$(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | wc -l)" + while [[ $FileNum -gt $ReservedNum ]]; do + OldFile="$(ls -rt /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | head -1)" + echoRgb "刪除文件:${OldFile%/*/*}" + rm -rf "${OldFile%/*/*}" + let "FileNum--" + done + [[ -f $(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null) && $(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null | wc -l) = 1 ]] && cp -r "$(ls /data/app/*/com.google.android.trichromelibrary_*/base.apk 2>/dev/null)" "$Backup_folder/nmsl.apk" + fi + fi + [[ $name = bin.mt.plus && -f $apk_path && ! -f $Backup/$name2.apk ]] && cp -r "$apk_path" "$Backup/$name2.apk" + unset ChineseName PackageName ; D=1 +} +#檢測數據位置進行備份 +Backup_data() { + unset zsize + case $1 in + user) Size="$userSize" && data_path="$path2/$name" ;; + data) Size="$dataSize" && data_path="$path/$1/$name" ;; + obb) Size="$obbSize" && data_path="$path/$1/$name" ;; + *) [[ -f $app_details ]] && Size="$(cat "$app_details" | awk "/$1Size/"'{print $1}' | cut -f2 -d '=' | tail -n1 | sed 's/\"//g')" ; data_path="$2" ; Compression_method=tar ; zsize=1 + esac + if [[ -d $data_path ]]; then + if [[ $Size != $(du -ks "$data_path" | awk '{print $1}') ]]; then + [[ $lxj -ge 95 ]] && echoRgb "$data空間不足,達到$lxj%" "0" && exit 2 + echoRgb "備份$1數據" "2" + case $1 in + user) + case $Compression_method in + tar|Tar|TAR) tar --exclude="${data_path##*/}/.ota" --exclude="${data_path##*/}/cache" --exclude="${data_path##*/}/lib" -cpf - -C "${data_path%/*}" "${data_path##*/}" 2>/dev/null | pv >"$Backup_folder/$1.tar" ;; + zstd|Zstd|ZSTD) tar --exclude="${data_path##*/}/.ota" --exclude="${data_path##*/}/cache" --exclude="${data_path##*/}/lib" -cpf - -C "${data_path%/*}" "${data_path##*/}" 2>/dev/null | pv | zstd -r -T0 -6 -q >"$Backup_folder/$1.tar.zst" ;; + lz4|Lz4|LZ4) tar --exclude="${data_path##*/}/.ota" --exclude="${data_path##*/}/cache" --exclude="${data_path##*/}/lib" -cpf - -C "${data_path%/*}" "${data_path##*/}" 2>/dev/null | pv | lz4 -1 >"$Backup_folder/$1.tar.lz4" ;; + esac ;; + *) + case $Compression_method in + tar|Tar|TAR) tar --exclude="Backup_"* -cPpf - "$data_path" 2>/dev/null | pv >"$Backup_folder/$1.tar" ;; + zstd|Zstd|ZSTD) tar --exclude="Backup_"* -cPpf - "$data_path" 2>/dev/null | pv | zstd -r -T0 -6 -q >"$Backup_folder/$1.tar.zst" ;; + lz4|Lz4|LZ4) tar --exclude="Backup_"* -cPpf - "$data_path" 2>/dev/null | pv | lz4 -1 >"$Backup_folder/$1.tar.lz4" ;; + esac ;; + esac + echo_log "備份$1數據" + if [[ $result = 0 ]]; then + if [[ $zsize != "" ]]; then + echo "#$1Size=\"$(du -ks "$data_path" | awk '{print $1}')\"" >>"$app_details" + else + echo "$1Size=\"$(du -ks "$data_path" | awk '{print $1}')\"" >>"$app_details" + fi + fi + else + echoRgb "$1數據無發生變化 跳過備份" + fi + else + echoRgb "$1數據不存在跳過備份" + fi +} +recovery_backup() { + echo "$name2 $name $apk_path2" >>"$script_path/應用列表.txt" + if [[ $i = $r ]]; then + if [[ -f $tools_path/META-INF/com/google/android/update-binary ]]; then + echoRgb "輸出用於recovery的備份卡刷包" ; rm -rf "$MODDIR/recovery卡刷備份.zip" ; mkdir -p "$MODDIR/tmp" + tar -cpf - -C "$tools_path" "META-INF" "script" "bin" "apk" | tar --delete "script/restore3" --delete "bin/busybox_path" --delete "bin/lz4" --delete "bin/zip" | pv | tar --recursive-unlink -xmpf - -C "$MODDIR/tmp" + (cd "$MODDIR/tmp" && zip -r "recovery卡刷備份.zip" *) + echo_log "打包卡刷包" + [[ $result = 0 ]] && (mv "$MODDIR/tmp/recovery卡刷備份.zip" "$MODDIR" && rm -rf "$MODDIR/tmp" "$script_path/應用列表.txt" ; echoRgb "輸出:$MODDIR/recovery卡刷備份.zip" "2") + else + echoRgb "update-binary卡刷腳本遺失" "0" + fi + fi +} +[[ $Lo = true ]] && { +echoRgb "選擇是否只備份split apk(分割apk檔)\n 如果你不知道這意味什麼請選擇音量下進行混合備份\n 音量上是,音量下不是" +get_version "是" "不是,混合備份" && Splist="$branch" +echoRgb "是否備份外部數據 即比如原神的數據包\n 音量上備份,音量下不備份" +get_version "備份" "不備份" && Backup_obb_data="$branch" +echoRgb "是否備份使用者數據\n 音量上備份,音量下不備份" +get_version "備份" "不備份" && Backup_user_data="$branch" +echoRgb "全部應用備份結束後是否備份自定義目錄\n 音量上備份,音量下不備份" +get_version "備份" "不備份" && backup_media="$branch" +echoRgb "單獨生成可供recovery中救急備份的卡刷包?\n 音量上生成,音量下備份應用+生成(混合)" +get_version "單獨生成" "備份應用+卡刷包" && Hybrid_backup="$branch" +} +echo "#不需要恢復還原的應用請在開頭注釋# 比如#xxxxxxxx 酷安" >"$script_path/應用列表.txt" +#開始循環$txt內的資料進行備份 +#記錄開始時間 +starttime1="$(date -u "+%s")" +TIME="$starttime1" +#記錄error次數起點 +ERROR=1 +{ +while [[ $i -le $r ]]; do + name="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n "${i}p" | awk '{print $2}')" + name2="$(cat "$txt" | grep -v "#" | sed -e '/^$/d' | sed -n "${i}p" | awk '{print $1}')" + [[ $name = "" ]] && echoRgb "警告! 應用列表.txt應用包名獲取失敗,可能修改有問題" "0" && exit 1 + apk_path="$(pm path "$name" | cut -f2 -d ':')" + apk_path2="$(echo "$apk_path" | head -1)" ; apk_path2="${apk_path2%/*}" + if [[ -d $apk_path2 ]]; then + if [[ $Hybrid_backup = false ]]; then + echoRgb "備份第$i個應用 總共$r個 剩下$((r-i))個應用" + if [[ $name2 = *! || $name2 = *! ]]; then + name2="$(echo "$name2" | sed 's/!//g ; s/!//g')" + echoRgb "跳過備份$name2 所有數據" "0" + No_backupdata=1 + else + [[ $No_backupdata != "" ]] && unset No_backupdata + fi + Backup_folder="$Backup/${name2}[${name}]" + app_details="$Backup_folder/app_details" + [[ -f $app_details ]] && . "$app_details" + lxj="$(df -h "$data" | awk 'END{print $4}' | sed 's/%//g')" + starttime2="$(date -u "+%s")" + echoRgb "備份$name2 ($name)" + [[ $name = com.tencent.mobileqq ]] && echo "QQ可能恢復備份失敗或是丟失聊天記錄,請自行用你信賴的應用備份" + [[ $name = com.tencent.mm ]] && echo "WX可能恢復備份失敗或是丟失聊天記錄,請自行用你信賴的應用備份" + apk_number="$(echo "$apk_path" | wc -l)" + if [[ $apk_number = 1 ]]; then + if [[ $Splist = false ]]; then + Backup_apk "非Split Apk" + else + echoRgb "非Split Apk跳過備份" && unset D + fi + else + Backup_apk "Split Apk支持備份" + fi + if [[ $D != "" && $result = 0 && $No_backupdata = "" ]]; then + if [[ $Backup_obb_data = true ]]; then + #備份data數據 + Backup_data "data" + #備份obb數據 + Backup_data "obb" + fi + #備份user數據 + [[ $Backup_user_data = true ]] && Backup_data "user" + fi + endtime 2 "$name2備份" + echoRgb "完成$((i*100/r))% $hx$(df -h "$data" | awk 'END{print "剩餘:"$3"使用率:"$4}')" + echoRgb + recovery_backup + else + recovery_backup + fi + else + echoRgb "$name2[$name]不在安裝列表,備份個寂寞?" "0" + fi + if [[ $i = $r ]]; then + endtime 1 "應用備份" + if [[ $backup_media = true && $Hybrid_backup = false ]]; then + echoRgb "備份結束,備份多媒體" + starttime1="$(date -u "+%s")" + Backup_folder="$Backup/媒體" + A=1 + B="$(echo "$Custom_path" | grep -v "#" | sed -e '/^$/d' | sed -n '$=')" + [[ ! -d $Backup_folder ]] && mkdir -p "$Backup_folder" + [[ ! -f $Backup_folder/恢復多媒體數據.sh ]] && cp -r "$script_path/restore3" "$Backup_folder/恢復多媒體數據.sh" + app_details="$Backup_folder/app_details" + [[ -f $app_details ]] && . "$app_details" + echo "$Custom_path" | grep -v "#" | sed -e '/^$/d' | while read; do + echoRgb "備份第$A個資料夾 總共$B個 剩下$((B-A))個" + Backup_data "${REPLY##*/}" "$REPLY" + echoRgb "完成$((A*100/B))% $hx$(df -h "$data" | awk 'END{print "剩餘:"$3"使用率:"$4}')" && let A++ + done + endtime 1 "自定義備份" + fi + fi + [[ $ERROR -ge 5 ]] && echoRgb "錯誤次數達到上限 環境已重設\n -請重新執行腳本" "0" && rm -rf "$filepath" && exit 2 + let i++ +done + +echoRgb "你要備份跑路?祝你卡米9008" "2" +#計算出備份大小跟差異性 +filesizee="$(du -ks "$Backup" | awk '{print $1}')" +dsize="$(($((filesizee - filesize)) / 1024))" +echoRgb "備份資料夾路徑:$Backup" "2" +echoRgb "備份資料夾總體大小$(du -ksh "$Backup" | awk '{print $1}')" +if [[ $dsize -gt 0 ]]; then + if [[ $((dsize / 1024)) -gt 0 ]]; then + echoRgb "本次備份: $((dsize / 1024))gb" + else + echoRgb "本次備份: ${dsize}mb" + fi +else + echoRgb "本次備份: $(($((filesizee - filesize)) * 1000 / 1024))kb" +fi +echoRgb "批量備份完成" +starttime1="$TIME" +endtime 1 "批量備份開始到結束" +exit 0 +}& +wait +longToast "批量備份完成" +Print "批量備份完成 執行過程請查看$Status_log" \ No newline at end of file diff --git a/生成應用列表.sh b/生成應用列表.sh new file mode 100644 index 0000000..984afcb --- /dev/null +++ b/生成應用列表.sh @@ -0,0 +1,45 @@ +#!/system/bin/sh +MODDIR="${0%/*}" +#鏈接腳本設置環境變量 +tools_path="$MODDIR/tools" +bin_path="$tools_path/bin" +[[ $(echo "$MODDIR" | grep -v 'mt') = "" ]] && echo "我他媽骨灰給你揚了撒了TM不解壓縮?用毛線 憨批" && exit 1 +[[ ! -d $tools_path ]] && echo " $tools_path目錄遺失" && exit 1 +[[ ! -f $MODDIR/backup_settings.conf ]] && echo "backup_settings.conf遺失" && exit 1 +. "$bin_path/bin.sh" +. "$MODDIR/backup_settings.conf" +system=" +com.google.android.apps.messaging +com.digibites.accubattery +com.google.android.inputmethod.latin +com.android.chrome" +# 获取默认桌面 +launcher_app="$(pm resolve-activity --brief -c android.intent.category.HOME -a android.intent.action.MAIN | grep '/' | cut -f1 -d '/')" +for launcher_app in $launcher_app; do + [[ $launcher_app != "android" ]] && [[ $(pgrep -f "$launcher_app" | grep -v 'grep' | wc -l) -ge 1 ]] && launcher_app="$launcher_app" +done +isBoolean "$path" && txtpath="$nsx" +[[ $txtpath = true ]] && txtpath="$PWD" || txtpath="$MODDIR" +nametxt="$txtpath/應用列表.txt" +[[ ! -e $nametxt ]] && echo '#不需要備份的應用請在開頭注釋# 比如#酷安 xxxxxxxx\n#不需要備份數據比如酷安! xxxxxxxx應用名後方加一個驚嘆號即可 注意是應用名不是包名' >"$nametxt" +echo >>"$nametxt" +echoRgb "請勿關閉腳本,等待提示結束" +i=1 +bn=118 +rm -rf "$MODDIR/tmp" +starttime1="$(date -u "+%s")" +appinfo -d " " -o ands,pn -pn $system $launcher_app -3 2>/dev/null | sort | sed 's/\///g ; s/\://g ; s/(//g ; s/)//g ; s/\[//g ; s/\]//g ; s/\-//g' | while read name; do + [[ $bn -ge 229 ]] && bn=118 + app_1=($name $name) + if [[ $(cat "$nametxt" | grep -oE "${app_1[1]}$") = "" ]]; then + echo "$name" >>"$nametxt" && xz=1 && [[ ! -e $MODDIR/tmp ]] && touch "$MODDIR/tmp" + echoRgb "$i.$name" + else + unset xz + fi + [[ $xz != "" ]] && let i++ bn++ +done +[[ -f $nametxt ]] && (sed -ie '/^$/d' "$nametxt" && rm -rf "$MODDIR/應用列表.txte") || (echoRgb "$nametxt生成失敗" "0" && exit 2) +endtime 1 +[[ ! -e $MODDIR/tmp ]] && echoRgb "無新增應用" || echoRgb "輸出包名結束 請查看$nametxt" +rm -rf "$MODDIR/tmp" \ No newline at end of file