executeToFile method
Executes an adb command and redirects the raw (binary) stdout of the
process to a file on the host, mimicking a shell redirection like
adb ... exec-out screencap -p > file.png.
Unlike execute (which decodes stdout as a string and would corrupt
binary data), this streams the process stdout bytes directly to
outputFile.
Implementation
Future<int> executeToFile(
List<String> arguments, {
required String outputFile,
bool runInShell = true,
bool checkIfRunning = true,
Duration? timeout,
bool debug = false,
}) async {
final time = DateTime.now();
if (debug) {
final timeString =
'${time.hour}:${time.minute}:${time.second}.${time.millisecond}';
debugPrint(
'[$timeString] Executing $_adbPath ${arguments.join(' ')} > $outputFile',
);
}
await init();
final process = await io.Process.start(
_adbPath!,
arguments,
runInShell: runInShell,
);
final sink = io.File(outputFile).openWrite();
final stderrBuffer = StringBuffer();
final stdoutDone = process.stdout.pipe(sink);
final stderrDone = process.stderr
.transform(utf8.decoder)
.forEach(stderrBuffer.write);
Future<int> exitCodeFuture = process.exitCode;
if (timeout != null) {
exitCodeFuture = exitCodeFuture.timeout(
timeout,
onTimeout: () {
process.kill();
return -1;
},
);
}
final exitCode = await exitCodeFuture;
await stdoutDone;
await stderrDone;
if (debug) {
final t2 = DateTime.now();
final elapsed = t2.difference(time).inMilliseconds;
final timeString =
'${t2.hour}:${t2.minute}:${t2.second}.${t2.millisecond}';
debugPrint('[$timeString] exitCode: $exitCode, elapsed: $elapsed ms');
}
if (checkIfRunning && exitCode != 0) {
final stderrString = stderrBuffer.toString();
if (stderrString.contains(AdbDaemonNotRunningException.trigger)) {
throw AdbDaemonNotRunningException(message: stderrString);
}
throw Exception(stderrString);
}
return exitCode;
}