Flutter 生成Apk&ipa包初始化环境-16

1,381 阅读3分钟

Flutter开发中经常使用到Flutter相关的命令分类: 安装Flutter相关的文件

1.配置Flutter相关的配置信息&环境构建

2.flutter创建项目

3.项目源代码分析

4.运行设备的初始化

5.测试相关

在开发中,我们经常使用到Flutter相关的命令来这些一些操作,FlutterSdk在安装包中flutter/bind/flutter命令是一个shell脚本,在安装的时候我们在环境变量中已经配置了查找路劲,在终端命令行中可以这几运行该命令安装flutter环境export PATH="$PATH:pwd/flutter/bin"在终端这些Flutter arg是可以直接调用flutter,安装FlutterSDK时,包括了开发工具和Flutter项目:

1.sdk相关配置

2.创建Flutter工程

3.开发框架、第三方库文件的依赖管理

4.源码分析工具

5.编译、运行

6.安装、测试

Flutter命令的作为一个flutter/bin/flutter进行执行。Flutter是使用shell进行编写,

#!/usr/bin/env bash
....
PROG_NAME="$(path_uri "$(follow_links "$BASH_SOURCE")")"
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
export FLUTTER_ROOT="$(cd "${BIN_DIR}/.." ; pwd -P)"

FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools"
SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot"
STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp"
SCRIPT_PATH="$FLUTTER_TOOLS_DIR/bin/flutter_tools.dart"
DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk"

DART="$DART_SDK_PATH/bin/dart"
PUB="$DART_SDK_PATH/bin/pub"
.......
"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"

该方法功能:

  • DART:是指FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart;
  • SNAPSHOT_PATH:是指FLUTTER_ROOT/bin/cache/flutter_tools.snapshot,这是由packages/flutter_tools项目编译所生成的产物文件。

dart执行flutter_tools.snapshot,其实也就是执行flutter_tools.dart的main()方法,也就是说将上述命令改为如下语句,则运行flutter命令可以执行本地flutter_tools的项目代码,可用于本地调试分析。

/bin/cache/dart-sdk/bin/dart $FLUTTER_TOOL_ARGS "$FLUTTER_ROOT/packages/flutter_tools/bin/flutter_tools.dart" "$@"

进一步分析flutter_tools.dart文件

flutter_tools.dart

下载官方的SDK和配置好环境路径之后,就可以运行SDK了,运行SDK的入口文件时flutter,作为入口文件,在文件的中构建相关的配置文件路径,使用dart命令来运行dart代码,可是这些dart相关的文件,使用shell脚本启动dart相关的文件之后就开始进入dart的世界,接下来分析dart的入口文件

在入口文件中,主要配置相关的参数,实现相关的命令行工具,构建脚本和环境的类:

1.args

2.Command相关的实现类

3.BuildRunner

4.BuildRunnerWebCompilationProxy

5.DwdsWebRunnerFactory

/// Main entry point for commands.
///
/// This function is intended to be used from the `flutter` command line tool.
Future<void> main(List<String> args) async {
  final bool verbose = args.contains('-v') || args.contains('--verbose');

  final bool doctor = (args.isNotEmpty && args.first == 'doctor') ||
      (args.length == 2 && verbose && args.last == 'doctor');
  final bool help = args.contains('-h') || args.contains('--help') ||
      (args.isNotEmpty && args.first == 'help') || (args.length == 1 && verbose);
  final bool muteCommandLogging = help || doctor;
  final bool verboseHelp = help && verbose;

  await runner.run(args, <FlutterCommand>[
    AnalyzeCommand(verboseHelp: verboseHelp),
    AssembleCommand(),
    AttachCommand(verboseHelp: verboseHelp),
    BuildCommand(verboseHelp: verboseHelp),
    ChannelCommand(verboseHelp: verboseHelp),
    CleanCommand(),
    ConfigCommand(verboseHelp: verboseHelp),
    CreateCommand(),
    DaemonCommand(hidden: !verboseHelp),
    DevicesCommand(),
    DoctorCommand(verbose: verbose),
    DriveCommand(),
    EmulatorsCommand(),
    FormatCommand(),
    GenerateCommand(),
    IdeConfigCommand(hidden: !verboseHelp),
    InjectPluginsCommand(hidden: !verboseHelp),
    InstallCommand(),
    LogsCommand(),
    MakeHostAppEditableCommand(),
    PackagesCommand(),
    PrecacheCommand(),
    RunCommand(verboseHelp: verboseHelp),
    ScreenshotCommand(),
    ShellCompletionCommand(),
    TestCommand(verboseHelp: verboseHelp),
    TrainingCommand(),
    UnpackCommand(),
    UpdatePackagesCommand(hidden: !verboseHelp),
    UpgradeCommand(),
    VersionCommand(),
  ], verbose: verbose,
     muteCommandLogging: muteCommandLogging,
     verboseHelp: verboseHelp,
     overrides: <Type, Generator>{
       // The build runner instance is not supported in google3 because
       // the build runner packages are not synced internally.
       CodeGenerator: () => const BuildRunner(),
       WebCompilationProxy: () => BuildRunnerWebCompilationProxy(),
       // The web runner is not supported internally because it depends
       // on dwds.
       WebRunnerFactory: () => DwdsWebRunnerFactory(),
     });
}

CommandRunner&Command

CommandRunner:负责执行相关的命令行工具(动态过程),实现类FlutterCommandRunner加载当前目录下的.packages第三方文件,加载环境变量和相关的运行文件

1.第三方包文件.packages

2.flutterEngine相关的信息

3.平台相关的信息,添加相关的文件到环境变量中

Command:构建命令,处理不同实现的子命令的构建过程

runner.run

1.初始化FlutterCommandRunner,加载第三方依赖库

2.加载所有的命令行实现类,进行初始化

3.初始化运行环境,这段代码是一个回调函数的调用方法,在后续的调用

4.运行代码到dartVM的Zoned中

5.runZoned<Future>


/// Runs the Flutter tool with support for the specified list of [commands].
Future<int> run(
  List<String> args,
  List<FlutterCommand> commands, {
  bool muteCommandLogging = false,
  bool verbose = false,
  bool verboseHelp = false,
  bool reportCrashes,
  String flutterVersion,
  Map<Type, Generator> overrides,
}) {
  reportCrashes ??= !isRunningOnBot;

  if (muteCommandLogging) {
    // Remove the verbose option; for help and doctor, users don't need to see
    // verbose logs.
    args = List<String>.from(args);
    args.removeWhere(
        (String option) => option == '-v' || option == '--verbose');
  }

  ///设置系统环境
  final FlutterCommandRunner runner =
      FlutterCommandRunner(verboseHelp: verboseHelp);

  ///添加实现的命令行工具,进行初始化
  commands.forEach(runner.addCommand);

  ///初始化运行环境
  return runInContext<int>(() async {
    // Initialize the system locale.
    final String systemLocale = await intl_standalone.findSystemLocale();
    intl.Intl.defaultLocale = intl.Intl.verifiedLocale(
      systemLocale,
      intl.NumberFormat.localeExists,
      onFailure: (String _) => 'en_US',
    );

    String getVersion() =>
        flutterVersion ??
        FlutterVersion.instance.getVersionString(redactUnknownBranches: true);
    Object firstError;
    StackTrace firstStackTrace;

    ///运行代码到dartVM的Zoned中
    return await runZoned<Future<int>>(() async {
      try {
        ///调用命令行实现子类
        await runner.run(args);
        return await _exit(0);
      } catch (error, stackTrace) {
        firstError = error;
        firstStackTrace = stackTrace;
        return await _handleToolError(
            error, stackTrace, verbose, args, reportCrashes, getVersion);
      }
    }, onError: (Object error, StackTrace stackTrace) async {
      // If sending a crash report throws an error into the zone, we don't want
      // to re-try sending the crash report with *that* error. Rather, we want
      // to send the original error that triggered the crash report.
      final Object e = firstError ?? error;
      final StackTrace s = firstStackTrace ?? stackTrace;
      await _handleToolError(e, s, verbose, args, reportCrashes, getVersion);
    });
  }, overrides: overrides);
}

runInContext

Flutter是一个跨平台的开发工具,在编译系统中需要处理不同平台的运行环境

1.加载构建的系统和相关的目录

2.加载第三方依赖

3.加载Android&IOS&Web&Window&Mac相关的内容

3.1.开发环境
3.2.sdk
3.3.开发工具
3.4.开发依赖管理工具链
3.5.设备管理&模拟器加载管理
3.6.操作系统工具
3.7.Snapshot生成工具
3.8.运行、调试工具
Future<T> runInContext<T>(
    FutureOr<T> runner(), {
      Map<Type, Generator> overrides,
    }) async {
  return await context.run<T>(
    name: 'global fallbacks',
    body: runner,
    overrides: overrides,
    fallbacks: <Type, Generator>{
      ///验证Android的License
      AndroidLicenseValidator: () => AndroidLicenseValidator(),

      ///加载AndroidSDK
      AndroidSdk: AndroidSdk.locateAndroidSdk,

      ///读取开发工具的配置参数
      AndroidStudio: AndroidStudio.latestValid,

      ///验证Android开发工具链
      AndroidValidator: () => AndroidValidator(),

      ///加载Android的Adb文件
      AndroidWorkflow: () => AndroidWorkflow(),

      ///打包不同平台的包
      ApplicationPackageFactory: () => ApplicationPackageFactory(),

      ///获取引擎模板
      Artifacts: () => CachedArtifacts(),

      ///打包assertBundle
      AssetBundleFactory: () => AssetBundleFactory.defaultInstance,
      BotDetector: () => const BotDetector(),

      ///配置构建系统参数
      BuildSystem: () => const BuildSystem(),

      ///配置缓存目录
      Cache: () => Cache(),

      ///devtools开发工具配置参数
      ChromeLauncher: () => const ChromeLauncher(),

      ///IOS构建工具
      CocoaPods: () => CocoaPods(),

      ///CocoaPods配置参数验证
      CocoaPodsValidator: () => const CocoaPodsValidator(),

      ///'.flutter_settings'
      Config: () => Config(),
      DevFSConfig: () => DevFSConfig(),

      ///查找开发主机上的连接设备
      DeviceManager: () => DeviceManager(),

      ///查找可用的doctor文件
      Doctor: () => const Doctor(),

      ///Doctor验证工具
      DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,

      ///Android&IOS模拟器管理工具
      EmulatorManager: () => EmulatorManager(),

      ///检查SDK的特征
      FeatureFlags: () => const FeatureFlags(),
      Flags: () => const EmptyFlags(),

      ///验证Flutter版本
      FlutterVersion: () => FlutterVersion(const SystemClock()),

      ///Fuchsia开发工具
      FuchsiaArtifacts: () => FuchsiaArtifacts.find(),
      FuchsiaDeviceTools: () => FuchsiaDeviceTools(),
      FuchsiaSdk: () => FuchsiaSdk(),
      FuchsiaWorkflow: () => FuchsiaWorkflow(),

      ///Snapshot生成工具
      GenSnapshot: () => const GenSnapshot(),

      ///热加载配置参数
      HotRunnerConfig: () => HotRunnerConfig(),

      ///获取设备信息
      IMobileDevice: () => IMobileDevice(),

      ///IOS模拟器工具
      IOSSimulatorUtils: () => IOSSimulatorUtils(),
      IOSWorkflow: () => const IOSWorkflow(),

      ///IOSKernel编译工具
      KernelCompilerFactory: () => const KernelCompilerFactory(),
      LinuxWorkflow: () => const LinuxWorkflow(),
      Logger: () => platform.isWindows ? WindowsStdoutLogger() : StdoutLogger(),
      MacOSWorkflow: () => const MacOSWorkflow(),
      MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),

      ///操作系统工具
      OperatingSystemUtils: () => OperatingSystemUtils(),
      SimControl: () => SimControl(),
      Stdio: () => const Stdio(),

      ///设计配置
      SystemClock: () => const SystemClock(),
      TimeoutConfiguration: () => const TimeoutConfiguration(),

      ///Flutter开发工具
      Usage: () => Usage(),
      UserMessages: () => UserMessages(),
      VisualStudio: () => VisualStudio(),
      VisualStudioValidator: () => const VisualStudioValidator(),

      ///web开发工具
      WebWorkflow: () => const WebWorkflow(),
      WindowsWorkflow: () => const WindowsWorkflow(),

      ///Xcode开发工具
      Xcode: () => Xcode(),
      XcodeValidator: () => const XcodeValidator(),
      XcodeProjectInterpreter: () => XcodeProjectInterpreter(),
    },
  );
}

AppContext

lib/executable.dart中的run方法中构建的overrides

lib/runner.dart的runInContext方法中传入的回调函数作为body

lib/src/context_runner.dartcontext.run中的fallbacks传入环境参数工具链、开发工具的加载的内容

AppContext:负责作为Zone和外部逻辑的的沟通渠道

Future<V> run<V>({
  @required FutureOr<V> body(),
  String name,
  Map<Type, Generator> overrides,
  Map<Type, Generator> fallbacks,
  ZoneSpecification zoneSpecification,
}) async {
  ///App的运行环境
  final AppContext child = AppContext._(
    this,
    name,
    Map<Type, Generator>.unmodifiable(overrides ?? const <Type, Generator>{}),
    Map<Type, Generator>.unmodifiable(fallbacks ?? const <Type, Generator>{}),
  );

  ///提交数据到DartVM真正运行
  return await runZoned<Future<V>>(
    () async => await body(),
    zoneValues: <_Key, AppContext>{_Key.key: child},
    zoneSpecification: zoneSpecification,
  );
}

在运行所需要的环境加载之后,就提交相关的逻辑到Zone中的运行执行body

///提交数据到DartVM真正运行
    return await runZoned<Future<V>>(
      () async => await body(),
      zoneValues: <_Key, AppContext>{_Key.key: child},
      zoneSpecification: zoneSpecification,
    );

AppContext:get获取虚拟机加载的资源

/// Gets the value associated with the specified [type], or `null` if no
/// such value has been associated.
T get<T>() {
  dynamic value = _generateIfNecessary(T, _overrides);
  if (value == null && _parent != null) {
    value = _parent.get<T>();
  }
  return _unboxNull(value ?? _generateIfNecessary(T, _fallbacks)) as T;
}

lib/runner.dart:body

1.设置系统环境

2.添加实现的命令行工具,进行初始化

3.初始化运行环境

4.运行代码到dartVM的Zoned中

5.调用命令行实现子类

body开始执行FlutterCommandRunnerrun方法,

/// Runs the Flutter tool with support for the specified list of [commands].
Future<int> run(
  List<String> args,
  List<FlutterCommand> commands, {
  bool muteCommandLogging = false,
  bool verbose = false,
  bool verboseHelp = false,
  bool reportCrashes,
  String flutterVersion,
  Map<Type, Generator> overrides,
}) {
  reportCrashes ??= !isRunningOnBot;

  if (muteCommandLogging) {
    // Remove the verbose option; for help and doctor, users don't need to see
    // verbose logs.
    args = List<String>.from(args);
    args.removeWhere(
        (String option) => option == '-v' || option == '--verbose');
  }

  ///设置系统环境
  final FlutterCommandRunner runner =
      FlutterCommandRunner(verboseHelp: verboseHelp);

  ///添加实现的命令行工具,进行初始化
  commands.forEach(runner.addCommand);

  ///初始化运行环境
  return runInContext<int>(() async {
    // Initialize the system locale.
    final String systemLocale = await intl_standalone.findSystemLocale();
    intl.Intl.defaultLocale = intl.Intl.verifiedLocale(
      systemLocale,
      intl.NumberFormat.localeExists,
      onFailure: (String _) => 'en_US',
    );

    String getVersion() =>
        flutterVersion ??
        FlutterVersion.instance.getVersionString(redactUnknownBranches: true);
    Object firstError;
    StackTrace firstStackTrace;

    ///运行代码到dartVM的Zoned中
    return await runZoned<Future<int>>(() async {
      try {
        ///调用命令行实现子类
        await runner.run(args);
        return await _exit(0);
      } catch (error, stackTrace) {
        firstError = error;
        firstStackTrace = stackTrace;
        return await _handleToolError(
            error, stackTrace, verbose, args, reportCrashes, getVersion);
      }
    }, onError: (Object error, StackTrace stackTrace) async {
      // If sending a crash report throws an error into the zone, we don't want
      // to re-try sending the crash report with *that* error. Rather, we want
      // to send the original error that triggered the crash report.
      final Object e = firstError ?? error;
      final StackTrace s = firstStackTrace ?? stackTrace;
      await _handleToolError(e, s, verbose, args, reportCrashes, getVersion);
    });
  }, overrides: overrides);
}

FlutterCommandRunner:run

1.初始化日志管理工具VerboseLogger 2.日志输出配置OutputPreferences 3.初始化本地文件系统LocalFileSystem 4.日志压缩管理addShutdownHook 5.缓存清理 6.查找FlutterEnginegetLocalEngine(自己编译或者是SDK自己编译的都是在这里进行查找)

@override
Future<void> runCommand(ArgResults topLevelResults) async {
  final Map<Type, dynamic> contextOverrides = <Type, dynamic>{
    Flags: Flags(topLevelResults),
  };

  // Check for verbose.
  if (topLevelResults['verbose']) {
    // Override the logger.
    contextOverrides[Logger] = VerboseLogger(logger);
  }

  // Don't set wrapColumns unless the user said to: if it's set, then all
  // wrapping will occur at this width explicitly, and won't adapt if the
  // terminal size changes during a run.
  int wrapColumn;
  if (topLevelResults.wasParsed('wrap-column')) {
    try {
      wrapColumn = int.parse(topLevelResults['wrap-column']);
      if (wrapColumn < 0) {
        throwToolExit(userMessages
            .runnerWrapColumnInvalid(topLevelResults['wrap-column']));
      }
    } on FormatException {
      throwToolExit(userMessages
          .runnerWrapColumnParseError(topLevelResults['wrap-column']));
    }
  }

  // If we're not writing to a terminal with a defined width, then don't wrap
  // anything, unless the user explicitly said to.
  final bool useWrapping = topLevelResults.wasParsed('wrap')
      ? topLevelResults['wrap']
      : io.stdio.terminalColumns == null ? false : topLevelResults['wrap'];
  contextOverrides[OutputPreferences] = OutputPreferences(
    wrapText: useWrapping,
    showColor: topLevelResults['color'],
    wrapColumn: wrapColumn,
  );

  if (topLevelResults['show-test-device'] ||
      topLevelResults['device-id'] == FlutterTesterDevices.kTesterDeviceId) {
    FlutterTesterDevices.showFlutterTesterDevice = true;
  }

  String recordTo = topLevelResults['record-to'];
  String replayFrom = topLevelResults['replay-from'];

  if (topLevelResults['bug-report']) {
    // --bug-report implies --record-to=<tmp_path>
    final Directory tempDir = const LocalFileSystem()
        .systemTempDirectory
        .createTempSync('flutter_tools_bug_report.');
    recordTo = tempDir.path;

    // Record the arguments that were used to invoke this runner.
    final File manifest = tempDir.childFile('MANIFEST.txt');
    final StringBuffer buffer = StringBuffer()
      ..writeln('# arguments')
      ..writeln(topLevelResults.arguments)
      ..writeln()
      ..writeln('# rest')
      ..writeln(topLevelResults.rest);
    await manifest.writeAsString(buffer.toString(), flush: true);

    // ZIP the recording up once the recording has been serialized.
    addShutdownHook(() async {
      final File zipFile =
      getUniqueFile(fs.currentDirectory, 'bugreport', 'zip');
      os.zip(tempDir, zipFile);
      printStatus(userMessages.runnerBugReportFinished(zipFile.basename));
    }, ShutdownStage.POST_PROCESS_RECORDING);
    addShutdownHook(
            () => tempDir.delete(recursive: true), ShutdownStage.CLEANUP);
  }

  assert(recordTo == null || replayFrom == null);

  if (recordTo != null) {
    recordTo = recordTo.trim();
    if (recordTo.isEmpty) throwToolExit(userMessages.runnerNoRecordTo);
    contextOverrides.addAll(<Type, dynamic>{
      ProcessManager: getRecordingProcessManager(recordTo),
      FileSystem: getRecordingFileSystem(recordTo),
      Platform: await getRecordingPlatform(recordTo),
    });
    VMService.enableRecordingConnection(recordTo);
  }

  if (replayFrom != null) {
    replayFrom = replayFrom.trim();
    if (replayFrom.isEmpty) throwToolExit(userMessages.runnerNoReplayFrom);
    contextOverrides.addAll(<Type, dynamic>{
      ProcessManager: await getReplayProcessManager(replayFrom),
      FileSystem: getReplayFileSystem(replayFrom),
      Platform: await getReplayPlatform(replayFrom),
    });
    VMService.enableReplayConnection(replayFrom);
  }

  // We must set Cache.flutterRoot early because other features use it (e.g.
  // enginePath's initializer uses it).
  final String flutterRoot =
      topLevelResults['flutter-root'] ?? defaultFlutterRoot;
  Cache.flutterRoot = fs.path.normalize(fs.path.absolute(flutterRoot));

  // Set up the tooling configuration.
  final String enginePath = _findEnginePath(topLevelResults);
  if (enginePath != null) {
    contextOverrides.addAll(<Type, dynamic>{
      Artifacts: Artifacts.getLocalEngine(
          enginePath, _findEngineBuildPath(topLevelResults, enginePath)),
    });
  }

  await context.run<void>(
    overrides:
    contextOverrides.map<Type, Generator>((Type type, dynamic value) {
      return MapEntry<Type, Generator>(type, () => value);
    }),
    body: () async {
      logger.quiet = topLevelResults['quiet'];

      if (platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true')
        await Cache.lock();

      if (topLevelResults['suppress-analytics'])
        flutterUsage.suppressAnalytics = true;

      _checkFlutterCopy();
      try {
        await FlutterVersion.instance.ensureVersionFile();
      } on FileSystemException catch (e) {
        printError(
            'Failed to write the version file to the artifact cache: "$e".');
        printError(
            'Please ensure you have permissions in the artifact cache directory.');
        throwToolExit('Failed to write the version file');
      }
      if (topLevelResults.command?.name != 'upgrade' &&
          topLevelResults['version-check']) {
        await FlutterVersion.instance.checkFlutterVersionFreshness();
      }

      if (topLevelResults.wasParsed('packages'))
        PackageMap.globalPackagesPath =
            fs.path.normalize(fs.path.absolute(topLevelResults['packages']));

      // See if the user specified a specific device.
      deviceManager.specifiedDeviceId = topLevelResults['device-id'];

      if (topLevelResults['version']) {
        flutterUsage.sendCommand('version');
        String status;
        if (topLevelResults['machine']) {
          status = const JsonEncoder.withIndent('  ')
              .convert(FlutterVersion.instance.toJson());
        } else {
          status = FlutterVersion.instance.toString();
        }
        printStatus(status);
        return;
      }

      if (topLevelResults['machine']) {
        throwToolExit(
            'The --machine flag is only valid with the --version flag.',
            exitCode: 2);
      }
      await super.runCommand(topLevelResults);
    },
  );
}

CommandRunner:runCommand

1.解析命令行传入的,并且进行解析构建运行命令

2.调用Command的子类FlutterCommand中的run方法

Future<T> runCommand(ArgResults topLevelResults) async {
    var argResults = topLevelResults;
    var commands = _commands;
    Command command;
    var commandString = executableName;

    while (commands.isNotEmpty) {
      ......

      // Step into the command.
      argResults = argResults.command;
      command = commands[argResults.name];
      command._globalResults = topLevelResults;
      command._argResults = argResults;
      commands = command._subcommands;
      commandString += " ${argResults.name}";
    }
    ........
    return (await command.run()) as T;
  }

FlutterCommand:run()

1.获取AppContext

2.运行代码到Zone中执行,初始化相关的上下文环境

3.调用子类的

@override
Future<void> run() {
  final DateTime startTime = systemClock.now();

  ///加载Flutter中的上下文加载的数据
  return context.run<void>(
    name: 'command',
    overrides: <Type, Generator>{FlutterCommand: () => this},
    body: () async {
      if (flutterUsage.isFirstRun) {
        flutterUsage.printWelcome();
      }
      final String commandPath = await usagePath;
      FlutterCommandResult commandResult;
      try {
        commandResult = await verifyThenRunCommand(commandPath);
      } on ToolExit {
        commandResult = const FlutterCommandResult(ExitStatus.fail);
        rethrow;
      } finally {
        final DateTime endTime = systemClock.now();
        printTrace(userMessages.flutterElapsedTime(
            name, getElapsedAsMilliseconds(endTime.difference(startTime))));
        _sendPostUsage(commandPath, commandResult, startTime, endTime);
      }
    },
  );
}

AppContext

获取加载到Zone中的资源

/// The current [AppContext], as determined by the [Zone] hierarchy.
///
/// This will be the first context found as we scan up the zone hierarchy, or
/// the "root" context if a context cannot be found in the hierarchy. The root
/// context will not have any values associated with it.
///
/// This is guaranteed to never return `null`.
AppContext get context =>
    Zone.current[_Key.key] as AppContext ?? AppContext._root;

FlutterCommand:verifyThenRunCommand

1.验证pubspec.yaml

2.验证flutter.yaml

3.加载不同平台的Artifacts

4.pubGet加载第三方包

5.初始化工程目录FlutterProject

6.加载工具链

7.设置不同平台的包文婧处理路劲和文件

8.运行runCommand执行实现的命令子类

@mustCallSuper
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
  await validateCommand();

  // Populate the cache. We call this before pub get below so that the sky_engine
  // package is available in the flutter cache for pub to find.
  if (shouldUpdateCache) {
    await cache.updateAll(await requiredArtifacts);
  }

  if (shouldRunPub) {
    await pubGet(context: PubContext.getVerifyContext(name));
    final FlutterProject project = FlutterProject.current();
    await project.ensureReadyForPlatformSpecificTooling(checkProjects: true);
  }

  setupApplicationPackages();

  if (commandPath != null) {
    final Map<CustomDimensions, String> additionalUsageValues =
        <CustomDimensions, String>{
      ...?await usageValues,
      CustomDimensions.commandHasTerminal:
          io.stdout.hasTerminal ? 'true' : 'false',
    };
    Usage.command(commandPath, parameters: additionalUsageValues);
  }

  return await runCommand();
}

RunCommand:runCommand

真正运行打包的过程,不同的平台都是在这个方法中开始进行打包,上面的执行构成都是在构成环境信息和相关的路径信息

1.初始化相关的运行设备

2.两种模式运行代码HotRunner、ColdRunner

3.调用上面的两种运行模式其中一种的runner.run方法开始调用本地编译环境开始编译不同平台的包

@override
Future<FlutterCommandResult> runCommand() async {
.......
遍历所有的工具
  for (Device device in devices) {
    if (await device.isLocalEmulator) {
......
  }

  if (hotMode) {
    for (Device device in devices) {
      if (!device.supportsHotReload)
        throwToolExit('Hot reload is not supported by ${device.name}. Run with --no-hot.');
    }
  }

  List<String> expFlags;
  if (argParser.options.containsKey(FlutterOptions.kEnableExperiment) &&
      argResults[FlutterOptions.kEnableExperiment].isNotEmpty) {
    expFlags = argResults[FlutterOptions.kEnableExperiment];
  }
  final List<FlutterDevice> flutterDevices = <FlutterDevice>[];
  final FlutterProject flutterProject = FlutterProject.current();
  for (Device device in devices) {
    final FlutterDevice flutterDevice = await FlutterDevice.create(
      device,
      flutterProject: flutterProject,
      trackWidgetCreation: argResults['track-widget-creation'],
      fileSystemRoots: argResults['filesystem-root'],
      fileSystemScheme: argResults['filesystem-scheme'],
      viewFilter: argResults['isolate-filter'],
      experimentalFlags: expFlags,
      target: argResults['target'],
      buildMode: getBuildMode(),
    );
    flutterDevices.add(flutterDevice);
  }
  // Only support "web mode" with a single web device due to resident runner
  // refactoring required otherwise.
  final bool webMode = featureFlags.isWebEnabled &&
                       devices.length == 1  &&
                       await devices.single.targetPlatform == TargetPlatform.web_javascript;

  ResidentRunner runner;
  final String applicationBinaryPath = argResults['use-application-binary'];
  if (hotMode && !webMode) {
    runner = HotRunner(
      flutterDevices,
      target: targetFile,
      debuggingOptions: _createDebuggingOptions(),
      benchmarkMode: argResults['benchmark'],
      applicationBinary: applicationBinaryPath == null
          ? null
          : fs.file(applicationBinaryPath),
      projectRootPath: argResults['project-root'],
      packagesFilePath: globalResults['packages'],
      dillOutputPath: argResults['output-dill'],
      stayResident: stayResident,
      ipv6: ipv6,
    );
  } else if (webMode) {
    runner = webRunnerFactory.createWebRunner(
      devices.single,
      target: targetFile,
      flutterProject: flutterProject,
      ipv6: ipv6,
      debuggingOptions: _createDebuggingOptions(),
    );
  } else {
    runner = ColdRunner(
      flutterDevices,
      target: targetFile,
      debuggingOptions: _createDebuggingOptions(),
      traceStartup: traceStartup,
      awaitFirstFrameWhenTracing: awaitFirstFrameWhenTracing,
      applicationBinary: applicationBinaryPath == null
          ? null
          : fs.file(applicationBinaryPath),
      ipv6: ipv6,
      stayResident: stayResident,
    );
  }

  DateTime appStartedTime;
  // Sync completer so the completing agent attaching to the resident doesn't
  // need to know about analytics.
  //
  // Do not add more operations to the future.
  final Completer<void> appStartedTimeRecorder = Completer<void>.sync();
  // This callback can't throw.
  unawaited(appStartedTimeRecorder.future.then<void>(
    (_) {
      appStartedTime = systemClock.now();
      if (stayResident) {
        TerminalHandler(runner)
          ..setupTerminal()
          ..registerSignalHandlers();
      }
    }
  ));

  final int result = await runner.run(
    appStartedCompleter: appStartedTimeRecorder,
    route: route,
  );
  if (result != 0) {
    throwToolExit(null, exitCode: result);
  }
  return FlutterCommandResult(
    ExitStatus.success,
    timingLabelParts: <String>[
      hotMode ? 'hot' : 'cold',
      getModeName(getBuildMode()),
      devices.length == 1
          ? getNameForTargetPlatform(await devices[0].targetPlatform)
          : 'multiple',
      devices.length == 1 && await devices[0].isLocalEmulator ? 'emulator' : null,
    ],
    endTimeOverride: appStartedTime,
  );
}

HotRunner

遍历所有的设备进行执行编译

@override
Future<int> run({
  Completer<DebugConnectionInfo> connectionInfoCompleter,
  Completer<void> appStartedCompleter,
  String route,
}) async {
  if (!fs.isFileSync(mainPath)) {
    String message = 'Tried to run $mainPath, but that file does not exist.';
    if (target == null)
      message += '\nConsider using the -t option to specify the Dart file to start.';
    printError(message);
    return 1;
  }

  firstBuildTime = DateTime.now();

  for (FlutterDevice device in flutterDevices) {
    final int result = await device.runHot(
      hotRunner: this,
      route: route,
    );
    if (result != 0) {
      return result;
    }
  }

  return attach(
    connectionInfoCompleter: connectionInfoCompleter,
    appStartedCompleter: appStartedCompleter,
  );
}

Device

不同的平台进行编译的的过程是通过Device来进行处理的,后面我们将对不同的平台进行编译,发布,运行处理