美文网首页
源码解读Flutter tools机制

源码解读Flutter tools机制

作者: 蜗牛是不是牛 | 来源:发表于2022-11-23 17:58 被阅读0次

    一、Flutter tools命令

    开发Flutter应用过程,经常会用过Flutter命令,比如flutter run可用于安装并运行Flutter应用,flutter build可用于构建产物,相信有不少人会好奇flutter命令背后的原理。 对于flutter命令的起点位于flutter sdk中路径/flutter/bin/目录中的flutter命令,该命令最终会调用到flutter/packages/flutter_tools工程。

    二、深入源码flutter命令

    2.1 flutter命令起点

    [-> /flutter/bin/flutter]

    ...
    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" $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项目编译所生成的产物文件。

    那么flutter命令等价于如下:

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

    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/packages/flutter_tools/目录。

    2.2 flutter_tools.main

    [-> flutter/packages/flutter_tools/bin/flutter_tools.dart]

    import 'package:flutter_tools/executable.dart' as executable;
    
    void main(List<String> args) {
      executable.main(args);  //[见小节2.3]
    }
    
    

    2.3 executable.main

    [-> lib/executable.dart]

    import 'runner.dart' as runner;
    
    Future<void> main(List<String> args) async {
      ...
      //[见小节2.4]
      await runner.run(args, <FlutterCommand>[
        AnalyzeCommand(verboseHelp: verboseHelp),
        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(),
        StopCommand(),
        TestCommand(verboseHelp: verboseHelp),
        TraceCommand(),
        TrainingCommand(),
        UpdatePackagesCommand(hidden: !verboseHelp),
        UpgradeCommand(),
        VersionCommand(),
      ], verbose: verbose,
         muteCommandLogging: muteCommandLogging,
         verboseHelp: verboseHelp,
         overrides: <Type, Generator>{
           CodeGenerator: () => const BuildRunner(),
         });
    }
    
    

    2.4 runner.run

    [-> lib/runner.dart]

    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,
    }) {
      ...
      //创建FlutterCommandRunner对象
      final FlutterCommandRunner runner = FlutterCommandRunner(verboseHelp: verboseHelp);
      //[见小节2.4.1] 将创建的命令对象都加入到_commands
      commands.forEach(runner.addCommand);
    
      return runInContext<int>(() async {
        ...
        // [见小节2.5]
        await runner.run(args);
        ...
      }, overrides: overrides);
    }
    
    

    2.4.1 addCommand

    [-> package:args/command_runner.dart]

    void addCommand(Command<T> command) {
      var names = [command.name]..addAll(command.aliases);
      for (var name in names) {
        _commands[name] = command;
        argParser.addCommand(name, command.argParser);
      }
      command._runner = this;
    }
    
    

    所有命令都加入到_commands。比如flutter run对应的命令对象为RunCommand,flutter build对应的命令对象为buildCommand。

    2.5 FlutterCommandRunner.run

    [-> lib/src/runner/flutter_command_runner.dart]

    class FlutterCommandRunner extends CommandRunner<void> {
    
      Future<void> run(Iterable<String> args) {
        return super.run(args); // [见小节2.6]
      }
    }
    
    

    2.6 CommandRunner.run

    [-> package:args/command_runner.dart]

    class CommandRunner<T> {
    
      Future<T> run(Iterable<String> args) =>
          new Future.sync(() => runCommand(parse(args))); //见下文
    
      Future<T> runCommand(ArgResults topLevelResults) async {
        var argResults = topLevelResults;
        var commands = _commands;
        Command command;
        var commandString = executableName;
    
        while (commands.isNotEmpty) {
          ...
          argResults = argResults.command;
          //根据命令名从命令列表中找到相应的命令
          command = commands[argResults.name];
          command._globalResults = topLevelResults;
          command._argResults = argResults;
          commands = command._subcommands;  //查找到子命令
          commandString += " ${argResults.name}";
        }
        // 执行真正对应命令的run()方法 [见小节2.7]
        return (await command.run()) as T;
      }
    }
    
    

    该方法会根据命令后通过循环遍历查找子命令,直到找到最后的命令为止。但这些命令都直接或者间接继承于FlutterCommand命令

    2.7 FlutterCommand.run

    [-> lib/src/runner/flutter_command.dart]

    abstract class FlutterCommand extends Command<void> {
    
      Future<void> run() {
        final DateTime startTime = systemClock.now();
    
        return context.run<void>(
          name: 'command',
          overrides: <Type, Generator>{FlutterCommand: () => this},
          body: () async {
            ...
            try {
              // [见小节2.8]
              commandResult = await verifyThenRunCommand(commandPath);
            } on ToolExit {
              commandResult = const FlutterCommandResult(ExitStatus.fail);
              rethrow;
            } finally {
              ...
            }
          },
        );
      }
    }
    
    

    2.8 FlutterCommand.verifyThenRunCommand

    [-> lib/src/runner/flutter_command.dart]

    abstract class FlutterCommand extends Command<void> {
    
      Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
        await validateCommand();
        if (shouldUpdateCache) {
          await cache.updateAll(await requiredArtifacts);
        }
        if (shouldRunPub) {
          //获取pub
          await pubGet(context: PubContext.getVerifyContext(name));
          final FlutterProject project = await FlutterProject.current();
          await project.ensureReadyForPlatformSpecificTooling();
        }
        setupApplicationPackages();
        ...
    
        // 执行真正对应的命令类
        return await runCommand();
      }
    }
    
    

    该方法先执行pubGet()用于下载pubspec.yaml里配置的依赖,该pub对应执行命令为:

    $flutterRoot/bin/cache/dart-sdk/bin/pub --verbosity=warning get --no-precompile
    
    

    最终执行真正对应的命令类的runCommand方法。

    来自:http://gityuan.com/2019/09/01/flutter_tool/

    相关文章

      网友评论

          本文标题:源码解读Flutter tools机制

          本文链接:https://www.haomeiwen.com/subject/qnqaxdtx.html