Created
March 7, 2022 11:43
-
-
Save jbruchanov/3f0293218de285b3c3c075859f79ea23 to your computer and use it in GitHub Desktop.
Very naive debug backup of android app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.text.SimpleDateFormat | |
/* | |
this is very !naive! implementation by making just a copy of defined files (probably doesn't handle spaces or special chars!) | |
1) define following `backupMap` and `removeBeforeRestore` | |
2) import it into the app build.gradle using `apply from: "$rootProject.projectDir/appbackup.gradle"` | |
3) and then just run: | |
#backup (see the BackupID e.g. 20220307-113423) | |
./gradlew app:appBackup | |
#restore | |
./gradlew app:appRestore -PBackupId=20220307-113423 | |
*/ | |
ext { | |
packageName = "YOUR_PACKAGE_ID" | |
dateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss") | |
//!naive implementation, probably doesn't handle spaces or special chars! | |
backupMap = [ | |
"app.xml" : "shared_prefs/app.xml", | |
"appDatabase": "databases/appDatabase" | |
] | |
removeBeforeRestore = backupMap.values() + [ | |
"databases/appDatabase-shm", | |
"databases/appDatabase-wal" | |
] | |
logDiv = "-".repeat(80) | |
} | |
private def runCmd(String cmd) { | |
def sout = new StringBuilder(), serr = new StringBuilder() | |
def proc = cmd.execute() | |
proc.consumeProcessOutput(sout, serr) | |
proc.waitForOrKill(5000L) | |
logger.debug("$cmd\nout> $sout\nerr> $serr") | |
} | |
private def killApp(String packageName) { | |
runCmd("adb shell am force-stop ${packageName}") | |
} | |
private File backup(File backupFolder, String packageName) { | |
def now = System.currentTimeMillis() | |
def resultFolder = new File(backupFolder, "${dateFormat.format(now)}") | |
resultFolder.mkdirs() | |
backupMap.forEach { name, path -> | |
def devPath = "/data/data/$packageName/$path" | |
def localPath = new File(resultFolder, name) | |
logger.quiet("$devPath --> $localPath") | |
runCmd("adb rm /sdcard/$name") | |
runCmd("adb shell run-as $packageName cp $devPath /sdcard/$name") | |
runCmd("adb pull /sdcard/$name $localPath") | |
runCmd("adb rm /sdcard/$name") | |
} | |
return resultFolder | |
} | |
private restore(File backupFolder, String packageName) { | |
removeBeforeRestore.forEach { | |
def devPath = "/data/data/$packageName/$it" | |
runCmd("adb shell run-as $packageName rm $devPath") | |
} | |
backupMap.forEach { name, path -> | |
def devPath = "/data/data/$packageName/$path" | |
def devFolder = new File("/data/data/$packageName/$path").parentFile | |
def localPath = new File(backupFolder, name) | |
logger.quiet("$localPath --> $devPath") | |
if (!localPath.exists()) { | |
throw new IllegalStateException("$logDiv\nExpected file: '${localPath}' doesn't exist!\n$logDiv") | |
} | |
runCmd("adb shell rm /sdcard/$name") | |
runCmd("adb push \"$localPath\" /sdcard/$name") | |
runCmd("adb shell run-as $packageName mkdir ${devFolder.name}") | |
runCmd("adb shell run-as $packageName mv /sdcard/$name $devPath") | |
} | |
} | |
tasks.register("appBackup") { | |
doLast { | |
def backupsDir = new File(it.project.rootProject.rootDir, "backups") | |
killApp(packageName) | |
def resultFolder = backup(backupsDir, packageName) | |
def resultLog = "BackupId: ${resultFolder.name}\n - ${resultFolder.absolutePath}" | |
logger.quiet("$logDiv\n$resultLog\n$logDiv") | |
} | |
} | |
tasks.register("appRestore") { | |
doLast { | |
if (!it.project.hasProperty("BackupId")) { | |
throw new IllegalArgumentException("${logDiv}\nMissing 'BackupId', pass it via ./gradlew appRestore -PBackupId=xyz\n${logDiv}") | |
} | |
def id = it.project.getProperty("BackupId") | |
def backupsDir = new File(it.project.rootProject.rootDir, "backups/$id") | |
if (!backupsDir.exists()) { | |
throw new IllegalArgumentException("$logDiv\nInvalid BackupId: ${id}\n'$backupsDir' doesn't exist!\n$logDiv") | |
} | |
killApp(packageName) | |
restore(backupsDir, packageName) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment