| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'dart:convert'; | |
| import 'dart:io'; | |
| late Process daemon; | |
| // To use, start from the console and enter: | |
| // version: print version | |
| // shutdown: terminate the server | |
| // start: start an app | |
| // stop: stop a running app | |
| // devices: list devices | |
| // emulators: list emulators | |
| // emulator-launch: launch an emulator, append the word coldBoot to cold boot the emulator. | |
| Future<void> main() async { | |
| daemon = await Process.start('dart', <String>['bin/flutter_tools.dart', 'daemon']); | |
| print('daemon process started, pid: ${daemon.pid}'); | |
| daemon.stdout | |
| .transform<String>(utf8.decoder) | |
| .transform<String>(const LineSplitter()) | |
| .listen((String line) => print('<== $line')); | |
| daemon.stderr.listen(stderr.add); | |
| stdout.write('> '); | |
| stdin.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(( | |
| String line, | |
| ) { | |
| final List<String> words = line.split(' '); | |
| if (line == 'version' || line == 'v') { | |
| _send(<String, dynamic>{'method': 'daemon.version'}); | |
| } else if (line == 'shutdown' || line == 'q') { | |
| _send(<String, dynamic>{'method': 'daemon.shutdown'}); | |
| } else if (words.first == 'start') { | |
| _send(<String, dynamic>{ | |
| 'method': 'app.start', | |
| 'params': <String, dynamic>{ | |
| 'deviceId': words[1], | |
| 'projectDirectory': words[2], | |
| 'launchMode': words[3], | |
| }, | |
| }); | |
| } else if (words.first == 'stop') { | |
| if (words.length > 1) { | |
| _send(<String, dynamic>{ | |
| 'method': 'app.stop', | |
| 'params': <String, dynamic>{'appId': words[1]}, | |
| }); | |
| } else { | |
| _send(<String, dynamic>{'method': 'app.stop'}); | |
| } | |
| } else if (words.first == 'restart') { | |
| if (words.length > 1) { | |
| _send(<String, dynamic>{ | |
| 'method': 'app.restart', | |
| 'params': <String, dynamic>{'appId': words[1]}, | |
| }); | |
| } else { | |
| _send(<String, dynamic>{'method': 'app.restart'}); | |
| } | |
| } else if (line == 'devices') { | |
| _send(<String, dynamic>{'method': 'device.getDevices'}); | |
| } else if (line == 'emulators') { | |
| _send(<String, dynamic>{'method': 'emulator.getEmulators'}); | |
| } else if (words.first == 'emulator-launch') { | |
| _send(<String, dynamic>{ | |
| 'method': 'emulator.launch', | |
| 'params': <String, dynamic>{ | |
| 'emulatorId': words[1], | |
| if (words.contains('coldBoot')) 'coldBoot': true, | |
| }, | |
| }); | |
| } else if (line == 'enable') { | |
| _send(<String, dynamic>{'method': 'device.enable'}); | |
| } else { | |
| _send(<String, dynamic>{'method': line.trim()}); | |
| } | |
| stdout.write('> '); | |
| }); | |
| // Print in the callback can't fail. | |
| unawaited( | |
| daemon.exitCode.then<int>((int code) { | |
| print('daemon exiting ($code)'); | |
| exit(code); | |
| }), | |
| ); | |
| } | |
| int _id = 0; | |
| void _send(Map<String, dynamic> map) { | |
| map['id'] = _id++; | |
| final str = '[${json.encode(map)}]'; | |
| daemon.stdin.writeln(str); | |
| print('==> $str'); | |
| } |