executeToFile method

Future<int> executeToFile(
  1. List<String> arguments, {
  2. required String outputFile,
  3. bool runInShell = true,
  4. bool checkIfRunning = true,
  5. Duration? timeout,
  6. bool debug = false,
})

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;
}