mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Add sky_tools start command and associated android support.
This commit is contained in:
parent
6bfd60f217
commit
8cac55a4e2
|
@ -14,11 +14,12 @@ import 'package:sky_tools/src/cache.dart';
|
|||
import 'package:sky_tools/src/init.dart';
|
||||
import 'package:sky_tools/src/install.dart';
|
||||
import 'package:sky_tools/src/run_mojo.dart';
|
||||
import 'package:sky_tools/src/start.dart';
|
||||
import 'package:sky_tools/src/stop.dart';
|
||||
|
||||
class FlutterCommandRunner extends CommandRunner {
|
||||
FlutterCommandRunner()
|
||||
: super('flutter', 'Manage your flutter app development.') {
|
||||
: super('flutter', 'Manage your Flutter app development.') {
|
||||
argParser.addFlag('verbose',
|
||||
abbr: 'v',
|
||||
negatable: false,
|
||||
|
@ -77,8 +78,7 @@ class FlutterCommandRunner extends CommandRunner {
|
|||
'This path is relative to sky-src-path. Not normally required.',
|
||||
defaultsTo: 'out/ios_sim_Release/');
|
||||
argParser.addOption('package-root',
|
||||
help: 'Path to your packages directory.',
|
||||
defaultsTo: 'packages');
|
||||
help: 'Path to your packages directory.', defaultsTo: 'packages');
|
||||
}
|
||||
|
||||
Future<int> runCommand(ArgResults topLevelResults) async {
|
||||
|
@ -144,11 +144,12 @@ void main(List<String> args) {
|
|||
});
|
||||
|
||||
new FlutterCommandRunner()
|
||||
..addCommand(new StopCommand())
|
||||
..addCommand(new BuildCommand())
|
||||
..addCommand(new CacheCommand())
|
||||
..addCommand(new InitCommand())
|
||||
..addCommand(new InstallCommand())
|
||||
..addCommand(new RunMojoCommand())
|
||||
..addCommand(new StartCommand())
|
||||
..addCommand(new StopCommand())
|
||||
..run(args);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
library sky_tools.device;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
@ -52,6 +54,7 @@ abstract class _Device {
|
|||
|
||||
class AndroidDevice extends _Device {
|
||||
static const String _ADB_PATH = 'adb';
|
||||
static const String _observatoryPort = '8181';
|
||||
static const String _serverPort = '9888';
|
||||
|
||||
static const String className = 'AndroidDevice';
|
||||
|
@ -233,6 +236,66 @@ class AndroidDevice extends _Device {
|
|||
return true;
|
||||
}
|
||||
|
||||
Future<bool> startServer(
|
||||
String target, bool poke, bool checked, AndroidApk apk) async {
|
||||
String serverRoot = '';
|
||||
String mainDart = '';
|
||||
String missingMessage = '';
|
||||
if (await FileSystemEntity.isDirectory(target)) {
|
||||
serverRoot = target;
|
||||
mainDart = path.join(serverRoot, 'lib', 'main.dart');
|
||||
missingMessage = 'Missing lib/main.dart in project: $serverRoot';
|
||||
} else {
|
||||
serverRoot = Directory.current.path;
|
||||
mainDart = target;
|
||||
missingMessage = '$mainDart does not exist.';
|
||||
}
|
||||
|
||||
if (!await FileSystemEntity.isFile(mainDart)) {
|
||||
_logging.severe(missingMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up port forwarding for observatory.
|
||||
String observatoryPortString = 'tcp:$_observatoryPort';
|
||||
runCheckedSync(
|
||||
[adbPath, 'forward', observatoryPortString, observatoryPortString]);
|
||||
|
||||
// Actually start the server.
|
||||
await Process.start('pub', ['run', 'sky_tools:sky_server', _serverPort],
|
||||
workingDirectory: serverRoot, mode: ProcessStartMode.DETACHED);
|
||||
|
||||
// Set up reverse port-forwarding so that the Android app can reach the
|
||||
// server running on localhost.
|
||||
String serverPortString = 'tcp:$_serverPort';
|
||||
runCheckedSync([adbPath, 'reverse', serverPortString, serverPortString]);
|
||||
|
||||
String relativeDartMain = path.relative(mainDart, from: serverRoot);
|
||||
String url = 'http://localhost:$_serverPort/$relativeDartMain';
|
||||
if (poke) {
|
||||
url += '?rand=${new Random().nextDouble()}';
|
||||
}
|
||||
|
||||
// Actually launch the app on Android.
|
||||
List<String> cmd = [
|
||||
adbPath,
|
||||
'shell',
|
||||
'am',
|
||||
'start',
|
||||
'-a',
|
||||
'android.intent.action.VIEW',
|
||||
'-d',
|
||||
url,
|
||||
];
|
||||
if (checked) {
|
||||
cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
|
||||
}
|
||||
cmd.add(apk.component);
|
||||
|
||||
runCheckedSync(cmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stop(AndroidApk apk) {
|
||||
// Turn off reverse port forwarding
|
||||
|
|
|
@ -19,6 +19,14 @@ class InstallCommand extends Command {
|
|||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
if (install()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
bool install() {
|
||||
bool installedSomewhere = false;
|
||||
|
||||
Map<BuildPlatform, ApplicationPackage> packages =
|
||||
|
@ -28,13 +36,9 @@ class InstallCommand extends Command {
|
|||
}
|
||||
ApplicationPackage androidApp = packages[BuildPlatform.android];
|
||||
if (androidApp != null && android.isConnected()) {
|
||||
installedSomewhere = installedSomewhere || android.installApp(androidApp);
|
||||
installedSomewhere = android.installApp(androidApp) || installedSomewhere;
|
||||
}
|
||||
|
||||
if (installedSomewhere) {
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
return installedSomewhere;
|
||||
}
|
||||
}
|
||||
|
|
71
packages/flutter_tools/lib/src/start.dart
Normal file
71
packages/flutter_tools/lib/src/start.dart
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library sky_tools.start;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:sky_tools/src/application_package.dart';
|
||||
import 'package:sky_tools/src/device.dart';
|
||||
import 'package:sky_tools/src/install.dart';
|
||||
import 'package:sky_tools/src/stop.dart';
|
||||
|
||||
final Logger _logging = new Logger('sky_tools.start');
|
||||
|
||||
class StartCommand extends Command {
|
||||
final name = 'start';
|
||||
final description = 'Start your Flutter app on attached devices.';
|
||||
AndroidDevice android = null;
|
||||
|
||||
StartCommand([this.android]) {
|
||||
argParser.addFlag('poke',
|
||||
negatable: false,
|
||||
help: 'Restart the connection to the server (Android only).');
|
||||
argParser.addFlag('checked',
|
||||
negatable: true,
|
||||
defaultsTo: true,
|
||||
help: 'Toggle Dart\'s checked mode.');
|
||||
argParser.addOption('target',
|
||||
defaultsTo: '.',
|
||||
abbr: 't',
|
||||
help: 'Target app path or filename to start.');
|
||||
if (android == null) {
|
||||
android = new AndroidDevice();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
bool startedSomewhere = false;
|
||||
bool poke = argResults['poke'];
|
||||
if (!poke) {
|
||||
StopCommand stopper = new StopCommand(android);
|
||||
stopper.stop();
|
||||
|
||||
// Only install if the user did not specify a poke
|
||||
InstallCommand installer = new InstallCommand(android);
|
||||
startedSomewhere = installer.install();
|
||||
}
|
||||
|
||||
bool startedOnAndroid = false;
|
||||
if (android.isConnected()) {
|
||||
Map<BuildPlatform, ApplicationPackage> packages =
|
||||
ApplicationPackageFactory.getAvailableApplicationPackages();
|
||||
ApplicationPackage androidApp = packages[BuildPlatform.android];
|
||||
|
||||
String target = path.absolute(argResults['target']);
|
||||
startedOnAndroid = await android.startServer(
|
||||
target, poke, argResults['checked'], androidApp);
|
||||
}
|
||||
|
||||
if (startedSomewhere || startedOnAndroid) {
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
35
packages/flutter_tools/test/start_test.dart
Normal file
35
packages/flutter_tools/test/start_test.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
library start_test;
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:sky_tools/src/application_package.dart';
|
||||
import 'package:sky_tools/src/start.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
defineTests() {
|
||||
group('start', () {
|
||||
test('returns 0 when Android is connected and ready to be started', () {
|
||||
ApplicationPackageFactory.srcPath = './';
|
||||
ApplicationPackageFactory.setBuildPath(
|
||||
BuildType.prebuilt, BuildPlatform.android, './');
|
||||
|
||||
MockAndroidDevice android = new MockAndroidDevice();
|
||||
when(android.isConnected()).thenReturn(true);
|
||||
when(android.installApp(any)).thenReturn(true);
|
||||
when(android.stop(any)).thenReturn(true);
|
||||
StartCommand command = new StartCommand(android);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
runner.run(['start']).then((int code) => expect(code, equals(0)));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue