build method

Future<int> build()

Executes the complete build process.

Orchestrates the entire build workflow including:

  1. Logging build configuration
  2. Running Flutter build command
  3. Moving output files to distribution directories
  4. Generating debug symbols (for Android release builds)

Returns the process exit code (0 indicates success).

The build process includes proper error handling and logging at each step to facilitate debugging build issues.

Implementation

Future<int> build() async {
  await registerSecrets();

  // Display build configuration before starting
  await printJob();

  // Get processed arguments with variable substitution
  final arguments = await this.arguments;
  final commandLine = ["flutter", "build", ...arguments].join(" ");

  logger.logCommand(commandLine);
  if (JobArguments.dryRun) return 0;

  // Start Flutter build process
  final Process process;
  try {
    process = await Process.start(
      "flutter",
      ["build", ...arguments],
      runInShell: true,
      includeParentEnvironment: true,
    );
  } on ProcessException catch (e) {
    logger.logError(
      "Unable to start `flutter`: ${e.message}. "
      "Make sure the Flutter SDK is installed and available in your PATH.",
    );
    return 127;
  }

  // Stream build output to logger
  process.stdout.transform(utf8.decoder).listen(logger.logDebug);
  process.stderr.transform(utf8.decoder).listen(logger.logErrorVerbose);

  // A flutter build produces nothing on screen below --verbose and can run
  // for minutes, so without this the CLI looks hung.
  final exitCode = await Spinner.run(
    'building $binaryType'
    '${flavor == null || flavor!.isEmpty ? '' : " ($flavor)"}',
    () => process.exitCode,
  );
  if (exitCode != 0) {
    // `distribute build android` returns straight to the process exit code,
    // so without this line a failed standalone build printed nothing at all:
    // flutter's own diagnostics go to logErrorVerbose, which is hidden below
    // --verbose. The runner adds its own per-job line on top, naming the job.
    logger.logError("flutter build failed with exit code $exitCode");
    if (!logger.isVerbose) {
      logger.logDetail(
        ColorizeLogger.fileLoggingEnabled
            ? "re-run with --verbose, or see ${ColorizeLogger.logFilePath}"
            : "re-run with --verbose to see flutter's output",
      );
    }
    return exitCode;
  }

  // Move output files to distribution directory
  final moveResult = await _moveOutputFiles();
  if (moveResult != 0) return moveResult;

  // Generate debug symbols for Android release builds
  if ((this is android_arguments.Arguments)) {
    if (buildMode == "release" &&
        (this as android_arguments.Arguments).generateDebugSymbols) {
      final zipResult = await _generateAndCopyZipSymbols();
      if (zipResult != 0) return zipResult;
    }
  }
  return exitCode;
}