Commit 5d3c55a1 authored by Devon Carew's avatar Devon Carew

Merge pull request #2812 from devoncarew/apk_build

refactor; fix apk warning
parents d2ff7a49 f1cdf6df
...@@ -18,11 +18,6 @@ import '../dart/sdk.dart'; ...@@ -18,11 +18,6 @@ import '../dart/sdk.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
// TODO(devoncarew): Possible improvements to flutter analyze --watch:
// - Auto-detect new issues introduced by changes and highlight then in the output.
// - Use ANSI codes to improve the display when the terminal supports it (screen
// clearing, cursor position manipulation, bold and faint codes, ...)
bool isDartFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('.dart'); bool isDartFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('.dart');
bool isDartTestFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('_test.dart'); bool isDartTestFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('_test.dart');
bool isDartBenchmarkFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('_bench.dart'); bool isDartBenchmarkFile(FileSystemEntity entry) => entry is File && entry.path.endsWith('_bench.dart');
...@@ -449,10 +444,13 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -449,10 +444,13 @@ class AnalyzeCommand extends FlutterCommand {
Future<int> _analyzeWatch() async { Future<int> _analyzeWatch() async {
List<String> directories; List<String> directories;
if (isFlutterRepo) { if (argResults['flutter-repo']) {
String root = path.absolute(ArtifactStore.flutterRoot);
directories = <String>[]; directories = <String>[];
directories.addAll(_gatherProjectPaths(path.absolute('examples'))); directories.addAll(_gatherProjectPaths(path.join(root, 'examples')));
directories.addAll(_gatherProjectPaths(path.absolute('packages'))); directories.addAll(_gatherProjectPaths(path.join(root, 'packages')));
directories.addAll(_gatherProjectPaths(path.join(root, 'dev')));
printStatus('Analyzing Flutter repository (${directories.length} projects).'); printStatus('Analyzing Flutter repository (${directories.length} projects).');
for (String projectPath in directories) for (String projectPath in directories)
printTrace(' ${path.relative(projectPath)}'); printTrace(' ${path.relative(projectPath)}');
...@@ -511,8 +509,6 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -511,8 +509,6 @@ class AnalyzeCommand extends FlutterCommand {
int issueDiff = issueCount - lastErrorCount; int issueDiff = issueCount - lastErrorCount;
lastErrorCount = issueCount; lastErrorCount = issueCount;
// TODO(devoncarew): If there were no issues found, and no change in the
// issue count, do we want to print anything?
if (firstAnalysis) if (firstAnalysis)
errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found'; errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found';
else if (issueDiff > 0) else if (issueDiff > 0)
......
...@@ -94,9 +94,8 @@ class _ApkBuilder { ...@@ -94,9 +94,8 @@ class _ApkBuilder {
'-I', _androidJar.path, '-I', _androidJar.path,
'-F', outputApk.path, '-F', outputApk.path,
]; ];
if (resources != null) { if (resources != null)
packageArgs.addAll(['-S', resources.absolute.path]); packageArgs.addAll(['-S', resources.absolute.path]);
}
packageArgs.add(artifacts.path); packageArgs.add(artifacts.path);
runCheckedSync(packageArgs); runCheckedSync(packageArgs);
} }
...@@ -146,7 +145,6 @@ class BuildApkCommand extends FlutterCommand { ...@@ -146,7 +145,6 @@ class BuildApkCommand extends FlutterCommand {
help: 'Android manifest XML file.'); help: 'Android manifest XML file.');
argParser.addOption('resources', argParser.addOption('resources',
abbr: 'r', abbr: 'r',
defaultsTo: _kDefaultResourcesPath,
help: 'Resources directory path.'); help: 'Resources directory path.');
argParser.addOption('output-file', argParser.addOption('output-file',
abbr: 'o', abbr: 'o',
...@@ -237,21 +235,15 @@ Future<_ApkComponents> _findApkComponents( ...@@ -237,21 +235,15 @@ Future<_ApkComponents> _findApkComponents(
components.jars = [new File(artifactPaths[1])]; components.jars = [new File(artifactPaths[1])];
components.libSkyShell = new File(artifactPaths[2]); components.libSkyShell = new File(artifactPaths[2]);
components.debugKeystore = new File(artifactPaths[3]); components.debugKeystore = new File(artifactPaths[3]);
components.resources = new Directory(resources); components.resources = resources == null ? null : new Directory(resources);
await parseServiceConfigs(components.services, jars: components.jars); await parseServiceConfigs(components.services, jars: components.jars);
if (!components.resources.existsSync()) { for (File file in [
// TODO(eseidel): This level should be higher when path is manually set.
printStatus('Cannot locate Resources: ${components.resources}, ignoring.');
components.resources = null;
}
for (File f in [
components.manifest, components.icuData, components.libSkyShell, components.debugKeystore components.manifest, components.icuData, components.libSkyShell, components.debugKeystore
]..addAll(components.jars)) { ]..addAll(components.jars)) {
if (!f.existsSync()) { if (!file.existsSync()) {
printError('Cannot locate file: ${f.path}'); printError('Cannot locate file: ${file.path}');
return null; return null;
} }
} }
...@@ -295,6 +287,7 @@ int _buildApk( ...@@ -295,6 +287,7 @@ int _buildApk(
ensureDirectoryExists(finalApk.path); ensureDirectoryExists(finalApk.path);
builder.align(unalignedApk, finalApk); builder.align(unalignedApk, finalApk);
printTrace('calculateSha: $outputFile');
File apkShaFile = new File('$outputFile.sha1'); File apkShaFile = new File('$outputFile.sha1');
apkShaFile.writeAsStringSync(calculateSha(finalApk)); apkShaFile.writeAsStringSync(calculateSha(finalApk));
...@@ -370,7 +363,7 @@ Future<int> buildAndroid({ ...@@ -370,7 +363,7 @@ Future<int> buildAndroid({
String enginePath, String enginePath,
bool force: false, bool force: false,
String manifest: _kDefaultAndroidManifestPath, String manifest: _kDefaultAndroidManifestPath,
String resources: _kDefaultResourcesPath, String resources,
String outputFile: _kDefaultOutputPath, String outputFile: _kDefaultOutputPath,
String target: '', String target: '',
String flxPath, String flxPath,
...@@ -392,6 +385,16 @@ Future<int> buildAndroid({ ...@@ -392,6 +385,16 @@ Future<int> buildAndroid({
return 0; return 0;
} }
if (resources != null) {
if (!FileSystemEntity.isDirectorySync(resources)) {
printError('Resources directory "$resources" not found.');
return 1;
}
} else {
if (FileSystemEntity.isDirectorySync(_kDefaultResourcesPath))
resources = _kDefaultResourcesPath;
}
BuildConfiguration config = configs.firstWhere( BuildConfiguration config = configs.firstWhere(
(BuildConfiguration bc) => bc.targetPlatform == TargetPlatform.android_arm (BuildConfiguration bc) => bc.targetPlatform == TargetPlatform.android_arm
); );
...@@ -411,11 +414,10 @@ Future<int> buildAndroid({ ...@@ -411,11 +414,10 @@ Future<int> buildAndroid({
} }
return _buildApk(components, flxPath, keystore, outputFile); return _buildApk(components, flxPath, keystore, outputFile);
} else { } else {
// Find the path to the main Dart file. // Find the path to the main Dart file; build the FLX.
String mainPath = findMainDartFile(target); String mainPath = findMainDartFile(target);
// Build the FLX.
String localBundlePath = await flx.buildFlx(toolchain, mainPath: mainPath); String localBundlePath = await flx.buildFlx(toolchain, mainPath: mainPath);
return _buildApk(components, localBundlePath, keystore, outputFile); return _buildApk(components, localBundlePath, keystore, outputFile);
} }
} }
......
...@@ -43,7 +43,7 @@ class BuildFlxCommand extends FlutterCommand { ...@@ -43,7 +43,7 @@ class BuildFlxCommand extends FlutterCommand {
if (compilerPath == null) if (compilerPath == null)
await downloadToolchain(); await downloadToolchain();
else else
toolchain = new Toolchain(compiler: new Compiler(compilerPath)); toolchain = new Toolchain(compiler: new SnapshotCompiler(compilerPath));
String outputPath = argResults['output-file']; String outputPath = argResults['output-file'];
......
...@@ -8,6 +8,7 @@ import 'dart:io'; ...@@ -8,6 +8,7 @@ import 'dart:io';
import '../android/android_device.dart'; import '../android/android_device.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../artifacts.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../device.dart'; import '../device.dart';
...@@ -386,24 +387,14 @@ class DeviceDomain extends Domain { ...@@ -386,24 +387,14 @@ class DeviceDomain extends Domain {
} }
} }
Map<String, dynamic> _deviceToMap(Device device) { Map<String, String> _deviceToMap(Device device) {
return <String, dynamic>{ return <String, String>{
'id': device.id, 'id': device.id,
'name': device.name, 'name': device.name,
'platform': _enumToString(device.platform) 'platform': getNameForTargetPlatform(device.platform)
}; };
} }
/// Take an enum value and get the best string representation of that.
///
/// toString() on enums returns 'EnumType.enumName'.
String _enumToString(dynamic enumValue) {
String str = '$enumValue';
if (str.contains('.'))
return str.substring(str.indexOf('.') + 1);
return str;
}
dynamic _toJsonable(dynamic obj) { dynamic _toJsonable(dynamic obj) {
if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null) if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null)
return obj; return obj;
......
...@@ -9,12 +9,6 @@ import '../globals.dart'; ...@@ -9,12 +9,6 @@ import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class LogsCommand extends FlutterCommand { class LogsCommand extends FlutterCommand {
@override
final String name = 'logs';
@override
final String description = 'Show log output for running Flutter apps.';
LogsCommand() { LogsCommand() {
argParser.addFlag('clear', argParser.addFlag('clear',
negatable: false, negatable: false,
...@@ -23,6 +17,12 @@ class LogsCommand extends FlutterCommand { ...@@ -23,6 +17,12 @@ class LogsCommand extends FlutterCommand {
); );
} }
@override
final String name = 'logs';
@override
final String description = 'Show log output for running Flutter apps.';
@override @override
bool get requiresProjectRoot => false; bool get requiresProjectRoot => false;
......
...@@ -41,7 +41,7 @@ class RefreshCommand extends FlutterCommand { ...@@ -41,7 +41,7 @@ class RefreshCommand extends FlutterCommand {
try { try {
String snapshotPath = path.join(tempDir.path, 'snapshot_blob.bin'); String snapshotPath = path.join(tempDir.path, 'snapshot_blob.bin');
int result = await toolchain.compiler.compile( int result = await toolchain.compiler.createSnapshot(
mainPath: argResults['target'], snapshotPath: snapshotPath mainPath: argResults['target'], snapshotPath: snapshotPath
); );
if (result != 0) { if (result != 0) {
......
...@@ -42,7 +42,7 @@ abstract class RunCommandBase extends FlutterCommand { ...@@ -42,7 +42,7 @@ abstract class RunCommandBase extends FlutterCommand {
defaultsTo: false, defaultsTo: false,
help: 'Start tracing during startup.'); help: 'Start tracing during startup.');
argParser.addOption('route', argParser.addOption('route',
help: 'Which route to load when starting the app.'); help: 'Which route to load when running the app.');
usesTargetOption(); usesTargetOption();
} }
...@@ -65,10 +65,10 @@ class RunCommand extends RunCommandBase { ...@@ -65,10 +65,10 @@ class RunCommand extends RunCommandBase {
RunCommand() { RunCommand() {
argParser.addFlag('full-restart', argParser.addFlag('full-restart',
defaultsTo: true, defaultsTo: true,
help: 'Stop any currently running application process before starting the app.'); help: 'Stop any currently running application process before running the app.');
argParser.addFlag('clear-logs', argParser.addFlag('clear-logs',
defaultsTo: true, defaultsTo: true,
help: 'Clear log history before starting the app.'); help: 'Clear log history before running the app.');
argParser.addFlag('start-paused', argParser.addFlag('start-paused',
defaultsTo: false, defaultsTo: false,
negatable: false, negatable: false,
...@@ -214,14 +214,12 @@ Future<int> startApp( ...@@ -214,14 +214,12 @@ Future<int> startApp(
await installApp(device, package); await installApp(device, package);
} }
bool startedSomething = false;
Map<String, dynamic> platformArgs = <String, dynamic>{}; Map<String, dynamic> platformArgs = <String, dynamic>{};
if (traceStartup != null) if (traceStartup != null)
platformArgs['trace-startup'] = traceStartup; platformArgs['trace-startup'] = traceStartup;
printStatus('Starting ${_getDisplayPath(mainPath)} on ${device.name}...'); printStatus('Running ${_getDisplayPath(mainPath)} on ${device.name}...');
bool result = await device.startApp( bool result = await device.startApp(
package, package,
...@@ -236,10 +234,8 @@ Future<int> startApp( ...@@ -236,10 +234,8 @@ Future<int> startApp(
); );
if (!result) { if (!result) {
printError('Error starting application on ${device.name}.'); printError('Error running application on ${device.name}.');
} else { } else {
startedSomething = true;
// If the user specified --start-paused (and the device supports it) then // If the user specified --start-paused (and the device supports it) then
// wait for the observatory port to become available before returning from // wait for the observatory port to become available before returning from
// `startApp()`. // `startApp()`.
...@@ -247,7 +243,7 @@ Future<int> startApp( ...@@ -247,7 +243,7 @@ Future<int> startApp(
await delayUntilObservatoryAvailable('localhost', debugPort); await delayUntilObservatoryAvailable('localhost', debugPort);
} }
return startedSomething ? 0 : 2; return result ? 0 : 2;
} }
/// Delay until the Observatory / service protocol is available. /// Delay until the Observatory / service protocol is available.
...@@ -257,6 +253,8 @@ Future<int> startApp( ...@@ -257,6 +253,8 @@ Future<int> startApp(
Future<Null> delayUntilObservatoryAvailable(String host, int port, { Future<Null> delayUntilObservatoryAvailable(String host, int port, {
Duration timeout: const Duration(seconds: 10) Duration timeout: const Duration(seconds: 10)
}) async { }) async {
printTrace('Waiting until Observatory is available (port $port).');
Stopwatch stopwatch = new Stopwatch()..start(); Stopwatch stopwatch = new Stopwatch()..start();
final String url = 'ws://$host:$port/ws'; final String url = 'ws://$host:$port/ws';
......
...@@ -18,15 +18,6 @@ import 'run.dart'; ...@@ -18,15 +18,6 @@ import 'run.dart';
const String _kDefaultBundlePath = 'build/app.flx'; const String _kDefaultBundlePath = 'build/app.flx';
class RunMojoCommand extends FlutterCommand { class RunMojoCommand extends FlutterCommand {
@override
final String name = 'run_mojo';
@override
final String description = 'Run a Flutter app in mojo (from github.com/domokit/mojo).';
@override
final bool hidden;
RunMojoCommand({ this.hidden: false }) { RunMojoCommand({ this.hidden: false }) {
argParser.addFlag('android', negatable: false, help: 'Run on an Android device'); argParser.addFlag('android', negatable: false, help: 'Run on an Android device');
argParser.addFlag('checked', negatable: false, help: 'Run Flutter in checked mode'); argParser.addFlag('checked', negatable: false, help: 'Run Flutter in checked mode');
...@@ -42,6 +33,15 @@ class RunMojoCommand extends FlutterCommand { ...@@ -42,6 +33,15 @@ class RunMojoCommand extends FlutterCommand {
argParser.addOption('devtools-path', help: 'Path to mojo devtools\' mojo_run command.'); argParser.addOption('devtools-path', help: 'Path to mojo devtools\' mojo_run command.');
} }
@override
final String name = 'run_mojo';
@override
final String description = 'Run a Flutter app in mojo (from github.com/domokit/mojo).';
@override
final bool hidden;
@override @override
bool get requiresProjectRoot => false; bool get requiresProjectRoot => false;
......
...@@ -10,6 +10,14 @@ import '../globals.dart'; ...@@ -10,6 +10,14 @@ import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class TraceCommand extends FlutterCommand { class TraceCommand extends FlutterCommand {
TraceCommand() {
argParser.addFlag('start', negatable: false, help: 'Start tracing.');
argParser.addFlag('stop', negatable: false, help: 'Stop tracing.');
argParser.addOption('out', help: 'Specify the path of the saved trace file.');
argParser.addOption('duration',
defaultsTo: '10', abbr: 'd', help: 'Duration in seconds to trace.');
}
@override @override
final String name = 'trace'; final String name = 'trace';
...@@ -22,14 +30,6 @@ class TraceCommand extends FlutterCommand { ...@@ -22,14 +30,6 @@ class TraceCommand extends FlutterCommand {
'time (controlled by --duration), and stop tracing. To explicitly control tracing, call trace\n' 'time (controlled by --duration), and stop tracing. To explicitly control tracing, call trace\n'
'with --start and later with --stop.'; 'with --start and later with --stop.';
TraceCommand() {
argParser.addFlag('start', negatable: false, help: 'Start tracing.');
argParser.addFlag('stop', negatable: false, help: 'Stop tracing.');
argParser.addOption('out', help: 'Specify the path of the saved trace file.');
argParser.addOption('duration',
defaultsTo: '10', abbr: 'd', help: 'Duration in seconds to trace.');
}
@override @override
bool get androidOnly => true; bool get androidOnly => true;
......
...@@ -177,7 +177,11 @@ Future<int> build( ...@@ -177,7 +177,11 @@ Future<int> build(
// In a precompiled snapshot, the instruction buffer contains script // In a precompiled snapshot, the instruction buffer contains script
// content equivalents // content equivalents
int result = await toolchain.compiler.compile(mainPath: mainPath, snapshotPath: snapshotPath, depfilePath: depfilePath, buildOutputPath: outputPath); int result = await toolchain.compiler.createSnapshot(
mainPath: mainPath,
snapshotPath: snapshotPath,
depfilePath: depfilePath
);
if (result != 0) { if (result != 0) {
printError('Failed to run the Flutter compiler. Exit code: $result'); printError('Failed to run the Flutter compiler. Exit code: $result');
return result; return result;
......
...@@ -99,14 +99,12 @@ class SimControl { ...@@ -99,14 +99,12 @@ class SimControl {
SimDevice _createTestDevice() { SimDevice _createTestDevice() {
SimDeviceType deviceType = _findSuitableDeviceType(); SimDeviceType deviceType = _findSuitableDeviceType();
if (deviceType == null) { if (deviceType == null)
return null; return null;
}
String runtime = _findSuitableRuntime(); String runtime = _findSuitableRuntime();
if (runtime == null) { if (runtime == null)
return null; return null;
}
// Delete any old test devices // Delete any old test devices
getDevices() getDevices()
...@@ -131,10 +129,8 @@ class SimControl { ...@@ -131,10 +129,8 @@ class SimControl {
if (usableTypes.isEmpty) { if (usableTypes.isEmpty) {
printError( printError(
'No suitable device type found.' 'No suitable device type found.\n'
'\n' 'You may launch an iOS Simulator manually and Flutter will attempt to use it.'
'You may launch an iOS Simulator manually and Flutter will attempt to '
'use it.'
); );
} }
...@@ -153,10 +149,8 @@ class SimControl { ...@@ -153,10 +149,8 @@ class SimControl {
if (usableRuntimes.isEmpty) { if (usableRuntimes.isEmpty) {
printError( printError(
'No suitable iOS runtime found.' 'No suitable iOS runtime found.\n'
'\n' 'You may launch an iOS Simulator manually and Flutter will attempt to use it.'
'You may launch an iOS Simulator manually and Flutter will attempt to '
'use it.'
); );
} }
...@@ -165,7 +159,7 @@ class SimControl { ...@@ -165,7 +159,7 @@ class SimControl {
void _deleteDevice(SimDevice device) { void _deleteDevice(SimDevice device) {
try { try {
List<String> args = [_xcrunPath, 'simctl', 'delete', device.name]; List<String> args = <String>[_xcrunPath, 'simctl', 'delete', device.name];
printTrace(args.join(' ')); printTrace(args.join(' '));
runCheckedSync(args); runCheckedSync(args);
} catch(e) { } catch(e) {
...@@ -426,9 +420,8 @@ class IOSSimulator extends Device { ...@@ -426,9 +420,8 @@ class IOSSimulator extends Device {
@override @override
String supportMessage() { String supportMessage() {
if (isSupported()) { if (isSupported())
return "Supported"; return "Supported";
}
return _supportMessage != null ? _supportMessage : "Unknown"; return _supportMessage != null ? _supportMessage : "Unknown";
} }
......
...@@ -21,11 +21,9 @@ class ServiceProtocolDiscovery { ...@@ -21,11 +21,9 @@ class ServiceProtocolDiscovery {
final DeviceLogReader _logReader; final DeviceLogReader _logReader;
Completer<int> _completer = new Completer<int>(); Completer<int> _completer = new Completer<int>();
/// The [Future] returned by this function will complete when the next /// The [Future] returned by this function will complete when the next service
/// service protocol port is found. /// protocol port is found.
Future<int> nextPort() { Future<int> nextPort() => _completer.future;
return _completer.future;
}
void _onLine(String line) { void _onLine(String line) {
int portNumber = 0; int portNumber = 0;
......
...@@ -11,12 +11,12 @@ import 'artifacts.dart'; ...@@ -11,12 +11,12 @@ import 'artifacts.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'build_configuration.dart'; import 'build_configuration.dart';
class Compiler { class SnapshotCompiler {
Compiler(this._path); SnapshotCompiler(this._path);
String _path; final String _path;
Future<int> compile({ Future<int> createSnapshot({
String mainPath, String mainPath,
String snapshotPath, String snapshotPath,
String depfilePath, String depfilePath,
...@@ -28,12 +28,10 @@ class Compiler { ...@@ -28,12 +28,10 @@ class Compiler {
'--package-root=${ArtifactStore.packageRoot}', '--package-root=${ArtifactStore.packageRoot}',
'--snapshot=$snapshotPath' '--snapshot=$snapshotPath'
]; ];
if (depfilePath != null) { if (depfilePath != null)
args.add('--depfile=$depfilePath'); args.add('--depfile=$depfilePath');
} if (buildOutputPath != null)
if (buildOutputPath != null) {
args.add('--build-output=$buildOutputPath'); args.add('--build-output=$buildOutputPath');
}
return runCommandAndStreamOutput(args); return runCommandAndStreamOutput(args);
} }
} }
...@@ -56,13 +54,13 @@ Future<String> _getCompilerPath(BuildConfiguration config) async { ...@@ -56,13 +54,13 @@ Future<String> _getCompilerPath(BuildConfiguration config) async {
class Toolchain { class Toolchain {
Toolchain({ this.compiler }); Toolchain({ this.compiler });
final Compiler compiler; final SnapshotCompiler compiler;
static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async { static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async {
for (BuildConfiguration config in configs) { for (BuildConfiguration config in configs) {
String compilerPath = await _getCompilerPath(config); String compilerPath = await _getCompilerPath(config);
if (compilerPath != null) if (compilerPath != null)
return new Toolchain(compiler: new Compiler(compilerPath)); return new Toolchain(compiler: new SnapshotCompiler(compilerPath));
} }
return null; return null;
} }
......
...@@ -28,11 +28,11 @@ class MockApplicationPackageStore extends ApplicationPackageStore { ...@@ -28,11 +28,11 @@ class MockApplicationPackageStore extends ApplicationPackageStore {
); );
} }
class MockCompiler extends Mock implements Compiler { class MockSnapshotCompiler extends Mock implements SnapshotCompiler {
} }
class MockToolchain extends Toolchain { class MockToolchain extends Toolchain {
MockToolchain() : super(compiler: new MockCompiler()); MockToolchain() : super(compiler: new MockSnapshotCompiler());
} }
class MockAndroidDevice extends Mock implements AndroidDevice { class MockAndroidDevice extends Mock implements AndroidDevice {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment