一倒堕、Flutter tools命令
1.1 概述
開發(fā)Flutter應用過程专控,經常會用過Flutter命令,比如flutter run可用于安裝并運行Flutter應用,flutter build可用于構建產物驯杜,相信有不少人會好奇flutter命令背后的原理。 對于flutter命令的起點位于flutter sdk中路徑/flutter/bin/目錄中的flutter命令,該命令最終會調用到flutter/packages/flutter_tools工程袖迎。
1.2 flutter命令參數表
列舉Flutter命令、對應類以及說明腺晾,實現見下文[小節(jié)2.3]燕锥。
名稱 | 對應類 | 說明 |
---|---|---|
create | CreateCommand | 創(chuàng)建新的Flutter項目 |
build | BuildCommand | Flutter構建命令 |
install | InstallCommand | 安裝Flutter應用到已連接設備 |
run | RunCommand | 運行Flutter應用于已連接設備 |
packages | PackagesCommand | 管理Flutter包的命令 |
devices | DevicesCommand | 列出所有已連接的設備 |
emulators | EmulatorsCommand | 列出,啟動悯蝉,創(chuàng)建模擬器 |
attach | AttachCommand | 附加到正在運行的應用程序 |
trace | TraceCommand | 開始和停止跟蹤正在運行的Flutter應用程序 |
logs | LogsCommand | 顯示Flutter應用運行中的log |
doctor | DoctorCommand | 顯示關于已安裝工具的信息 |
upgrade | UpgradeCommand | 升級Flutter |
clean | CleanCommand | 刪除build/和.dart_tool/ 目錄 |
analyze | AnalyzeCommand | 分析項目Dart代碼 |
format | FormatCommand | 格式化一個或多個dart文件 |
config | ConfigCommand | 配置Flutter settings |
drive | DriveCommand | 為當前項目運行Flutter Driver測試 |
test | TestCommand | 為當前項目運行Flutter 單元測試 |
另外归形,對于flutter build有子命令,其子命令的對應類及說明如下:
命令 | 對應類 | 說明 |
---|---|---|
build aot | BuildAotCommand | 構建AOT編譯產物 |
build apk | BuildApkCommand | 構建Android APK |
build ios | BuildIOSCommand | 構建iOS應用bundle |
build appbundle | BuildAppBundleCommand | 構建Android應用bundle |
build bundle | BuildBundleCommand | 構建Flutter assets |
比如flutter run則執(zhí)行RunCommand.runCommand()鼻由,flutter install則執(zhí)行InstallCommand.runCommand()暇榴。
二、深入源碼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"
//真正的執(zhí)行邏輯
"$DART" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
該方法功能:
-
FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart蕉世;
-
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執(zhí)行flutter_tools.snapshot狠轻,其實也就是執(zhí)行flutter_tools.dart的main()方法奸例,也就是說將上述命令改為如下語句,則運行flutter命令可以執(zhí)行本地flutter_tools的項目代碼向楼,可用于本地調試分析查吊。
/bin/cache/dart-sdk/bin/dart $FLUTTER_TOOL_ARGS "$FLUTTER_ROOT/packages/flutter_tools/bin/flutter_tools.dart" "$@"
接下來,執(zhí)行流程進入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); //[見小節(jié)2.3]
}
2.3 executable.main
[-> lib/executable.dart]
import 'runner.dart' as runner;
Future<void> main(List<String> args) async {
...
//[見小節(jié)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,
}) {
...
//創(chuàng)建FlutterCommandRunner對象
final FlutterCommandRunner runner = FlutterCommandRunner(verboseHelp: verboseHelp);
//[見小節(jié)2.4.1] 將創(chuàng)建的命令對象都加入到_commands
commands.forEach(runner.addCommand);
return runInContext<int>(() async {
...
// [見小節(jié)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); // [見小節(jié)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}";
}
// 執(zhí)行真正對應命令的run()方法 [見小節(jié)2.7]
return (await command.run()) as T;
}
}
該方法會根據命令后通過循環(huán)遍歷查找子命令箭阶,直到找到最后的命令為止。但這些命令都直接或者間接繼承于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 {
// [見小節(jié)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();
...
// 執(zhí)行真正對應的命令類
return await runCommand();
}
}
該方法先執(zhí)行pubGet()用于下載pubspec.yaml里配置的依賴戈鲁,該pub對應執(zhí)行命令為:
$flutterRoot/bin/cache/dart-sdk/bin/pub --verbosity=warning get --no-precompile
本文轉自 http://gityuan.com/2019/09/01/flutter_tool/仇参,如有侵權,請聯系刪除婆殿。