Commit 1328562e authored by Devon Carew's avatar Devon Carew

Merge pull request #1656 from devoncarew/gen_refactoring

General flutter_tools refactoring
parents 01a5b837 9e6d45cb
...@@ -2,16 +2,14 @@ ...@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
library flutter_tools;
import 'dart:async'; import 'dart:async';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'src/flx.dart' as flx; import 'src/flx.dart' as flx;
/// Assembles a Flutter .flx file from a pre-existing manifest descriptor /// Assembles a Flutter .flx file from a pre-existing manifest descriptor and a
/// and a pre-compiled snapshot. /// pre-compiled snapshot.
Future<int> assembleFlx({ Future<int> assembleFlx({
Map manifestDescriptor: const {}, Map manifestDescriptor: const {},
ArchiveFile snapshotFile: null, ArchiveFile snapshotFile: null,
......
...@@ -19,7 +19,7 @@ class Adb { ...@@ -19,7 +19,7 @@ class Adb {
final String adbPath; final String adbPath;
Map<String, String> _idToNameCache = <String, String>{}; final Map<String, String> _idToNameCache = <String, String>{};
bool exists() { bool exists() {
try { try {
......
...@@ -35,36 +35,16 @@ class AndroidDeviceDiscovery extends DeviceDiscovery { ...@@ -35,36 +35,16 @@ class AndroidDeviceDiscovery extends DeviceDiscovery {
} }
class AndroidDevice extends Device { class AndroidDevice extends Device {
static final String defaultDeviceID = 'default_android_device'; AndroidDevice(
String id, {
String productID; this.productID,
String modelID; this.modelID,
String deviceCodeName; this.deviceCodeName,
bool _connected;
String _adbPath;
String get adbPath => _adbPath;
bool _hasAdb = false;
bool _hasValidAndroid = false;
factory AndroidDevice({
String id: null,
String productID: null,
String modelID: null,
String deviceCodeName: null,
bool connected bool connected
}) { }) : super(id) {
AndroidDevice device = Device.unique(id ?? defaultDeviceID, (String id) => new AndroidDevice.fromId(id));
device.productID = productID;
device.modelID = modelID;
device.deviceCodeName = deviceCodeName;
if (connected != null) if (connected != null)
device._connected = connected; _connected = connected;
return device;
}
/// This constructor is intended as protected access; prefer [AndroidDevice].
AndroidDevice.fromId(id) : super.fromId(id) {
_adbPath = getAdbPath(); _adbPath = getAdbPath();
_hasAdb = _checkForAdb(); _hasAdb = _checkForAdb();
...@@ -78,6 +58,16 @@ class AndroidDevice extends Device { ...@@ -78,6 +58,16 @@ class AndroidDevice extends Device {
} }
} }
final String productID;
final String modelID;
final String deviceCodeName;
bool _connected;
String _adbPath;
String get adbPath => _adbPath;
bool _hasAdb = false;
bool _hasValidAndroid = false;
static String getAndroidSdkPath() { static String getAndroidSdkPath() {
if (Platform.environment.containsKey('ANDROID_HOME')) { if (Platform.environment.containsKey('ANDROID_HOME')) {
String androidHomeDir = Platform.environment['ANDROID_HOME']; String androidHomeDir = Platform.environment['ANDROID_HOME'];
...@@ -98,12 +88,7 @@ class AndroidDevice extends Device { ...@@ -98,12 +88,7 @@ class AndroidDevice extends Device {
} }
List<String> adbCommandForDevice(List<String> args) { List<String> adbCommandForDevice(List<String> args) {
List<String> result = <String>[adbPath]; return <String>[adbPath, '-s', id]..addAll(args);
if (id != defaultDeviceID) {
result.addAll(['-s', id]);
}
result.addAll(args);
return result;
} }
bool _isValidAdbVersion(String adbVersion) { bool _isValidAdbVersion(String adbVersion) {
...@@ -132,12 +117,12 @@ class AndroidDevice extends Device { ...@@ -132,12 +117,12 @@ class AndroidDevice extends Device {
bool _checkForAdb() { bool _checkForAdb() {
try { try {
String adbVersion = runCheckedSync([adbPath, 'version']); String adbVersion = runCheckedSync(<String>[adbPath, 'version']);
if (_isValidAdbVersion(adbVersion)) { if (_isValidAdbVersion(adbVersion)) {
return true; return true;
} }
String locatedAdbPath = runCheckedSync(['which', 'adb']); String locatedAdbPath = runCheckedSync(<String>['which', 'adb']);
printError('"$locatedAdbPath" is too old. ' printError('"$locatedAdbPath" is too old. '
'Please install version 1.0.32 or later.\n' 'Please install version 1.0.32 or later.\n'
'Try setting ANDROID_HOME to the path to your Android SDK install. ' 'Try setting ANDROID_HOME to the path to your Android SDK install. '
...@@ -157,18 +142,18 @@ class AndroidDevice extends Device { ...@@ -157,18 +142,18 @@ class AndroidDevice extends Device {
// output lines like this, which we want to ignore: // output lines like this, which we want to ignore:
// adb server is out of date. killing.. // adb server is out of date. killing..
// * daemon started successfully * // * daemon started successfully *
runCheckedSync(adbCommandForDevice(['start-server'])); runCheckedSync(adbCommandForDevice(<String>['start-server']));
String ready = runSync(adbCommandForDevice(['shell', 'echo', 'ready'])); String ready = runSync(adbCommandForDevice(<String>['shell', 'echo', 'ready']));
if (ready.trim() != 'ready') { if (ready.trim() != 'ready') {
printTrace('Android device not found.'); printTrace('Android device not found.');
return false; return false;
} }
// Sample output: '22' // Sample output: '22'
String sdkVersion = String sdkVersion = runCheckedSync(
runCheckedSync(adbCommandForDevice(['shell', 'getprop', 'ro.build.version.sdk'])) adbCommandForDevice(<String>['shell', 'getprop', 'ro.build.version.sdk'])
.trimRight(); ).trimRight();
int sdkVersionParsed = int sdkVersionParsed =
int.parse(sdkVersion, onError: (String source) => null); int.parse(sdkVersion, onError: (String source) => null);
...@@ -194,7 +179,7 @@ class AndroidDevice extends Device { ...@@ -194,7 +179,7 @@ class AndroidDevice extends Device {
} }
String _getDeviceApkSha1(ApplicationPackage app) { String _getDeviceApkSha1(ApplicationPackage app) {
return runCheckedSync(adbCommandForDevice(['shell', 'cat', _getDeviceSha1Path(app)])); return runCheckedSync(adbCommandForDevice(<String>['shell', 'cat', _getDeviceSha1Path(app)]));
} }
String _getSourceSha1(ApplicationPackage app) { String _getSourceSha1(ApplicationPackage app) {
...@@ -208,10 +193,10 @@ class AndroidDevice extends Device { ...@@ -208,10 +193,10 @@ class AndroidDevice extends Device {
@override @override
bool isAppInstalled(ApplicationPackage app) { bool isAppInstalled(ApplicationPackage app) {
if (!isConnected()) { if (!isConnected())
return false; return false;
}
if (runCheckedSync(adbCommandForDevice(['shell', 'pm', 'path', app.id])) == '') { if (runCheckedSync(adbCommandForDevice(<String>['shell', 'pm', 'path', app.id])) == '') {
printTrace('TODO(iansf): move this log to the caller. ${app.name} is not on the device. Installing now...'); printTrace('TODO(iansf): move this log to the caller. ${app.name} is not on the device. Installing now...');
return false; return false;
} }
...@@ -284,21 +269,21 @@ class AndroidDevice extends Device { ...@@ -284,21 +269,21 @@ class AndroidDevice extends Device {
this.clearLogs(); this.clearLogs();
String deviceTmpPath = '/data/local/tmp/dev.flx'; String deviceTmpPath = '/data/local/tmp/dev.flx';
runCheckedSync(adbCommandForDevice(['push', bundlePath, deviceTmpPath])); runCheckedSync(adbCommandForDevice(<String>['push', bundlePath, deviceTmpPath]));
List<String> cmd = adbCommandForDevice([ List<String> cmd = adbCommandForDevice(<String>[
'shell', 'am', 'start', 'shell', 'am', 'start',
'-a', 'android.intent.action.RUN', '-a', 'android.intent.action.RUN',
'-d', deviceTmpPath, '-d', deviceTmpPath,
'-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP '-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP
]); ]);
if (checked) if (checked)
cmd.addAll(['--ez', 'enable-checked-mode', 'true']); cmd.addAll(<String>['--ez', 'enable-checked-mode', 'true']);
if (traceStartup) if (traceStartup)
cmd.addAll(['--ez', 'trace-startup', 'true']); cmd.addAll(<String>['--ez', 'trace-startup', 'true']);
if (startPaused) if (startPaused)
cmd.addAll(['--ez', 'start-paused', 'true']); cmd.addAll(<String>['--ez', 'start-paused', 'true']);
if (route != null) if (route != null)
cmd.addAll(['--es', 'route', route]); cmd.addAll(<String>['--es', 'route', route]);
cmd.add(apk.launchActivity); cmd.add(apk.launchActivity);
runCheckedSync(cmd); runCheckedSync(cmd);
return true; return true;
...@@ -345,7 +330,7 @@ class AndroidDevice extends Device { ...@@ -345,7 +330,7 @@ class AndroidDevice extends Device {
Future<bool> stopApp(ApplicationPackage app) async { Future<bool> stopApp(ApplicationPackage app) async {
final AndroidApk apk = app; final AndroidApk apk = app;
runSync(adbCommandForDevice(['shell', 'am', 'force-stop', apk.id])); runSync(adbCommandForDevice(<String>['shell', 'am', 'force-stop', apk.id]));
return true; return true;
} }
...@@ -353,13 +338,13 @@ class AndroidDevice extends Device { ...@@ -353,13 +338,13 @@ class AndroidDevice extends Device {
TargetPlatform get platform => TargetPlatform.android; TargetPlatform get platform => TargetPlatform.android;
void clearLogs() { void clearLogs() {
runSync(adbCommandForDevice(['logcat', '-c'])); runSync(adbCommandForDevice(<String>['logcat', '-c']));
} }
DeviceLogReader createLogReader() => new _AdbLogReader(this); DeviceLogReader createLogReader() => new _AdbLogReader(this);
void startTracing(AndroidApk apk) { void startTracing(AndroidApk apk) {
runCheckedSync(adbCommandForDevice([ runCheckedSync(adbCommandForDevice(<String>[
'shell', 'shell',
'am', 'am',
'broadcast', 'broadcast',
...@@ -371,18 +356,18 @@ class AndroidDevice extends Device { ...@@ -371,18 +356,18 @@ class AndroidDevice extends Device {
// Return the most recent timestamp in the Android log. The format can be // Return the most recent timestamp in the Android log. The format can be
// passed to logcat's -T option. // passed to logcat's -T option.
String lastLogcatTimestamp() { String lastLogcatTimestamp() {
String output = runCheckedSync(adbCommandForDevice(['logcat', '-v', 'time', '-t', '1'])); String output = runCheckedSync(adbCommandForDevice(<String>['logcat', '-v', 'time', '-t', '1']));
RegExp timeRegExp = new RegExp(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}', multiLine: true); RegExp timeRegExp = new RegExp(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}', multiLine: true);
Match timeMatch = timeRegExp.firstMatch(output); Match timeMatch = timeRegExp.firstMatch(output);
return timeMatch[0]; return timeMatch[0];
} }
Future<String> stopTracing(AndroidApk apk, { String outPath: null }) async { Future<String> stopTracing(AndroidApk apk, { String outPath }) async {
// Workaround for logcat -c not always working: // Workaround for logcat -c not always working:
// http://stackoverflow.com/questions/25645012/logcat-on-android-l-not-clearing-after-unplugging-and-reconnecting // http://stackoverflow.com/questions/25645012/logcat-on-android-l-not-clearing-after-unplugging-and-reconnecting
String beforeStop = lastLogcatTimestamp(); String beforeStop = lastLogcatTimestamp();
runCheckedSync(adbCommandForDevice([ runCheckedSync(adbCommandForDevice(<String>[
'shell', 'shell',
'am', 'am',
'broadcast', 'broadcast',
...@@ -396,7 +381,7 @@ class AndroidDevice extends Device { ...@@ -396,7 +381,7 @@ class AndroidDevice extends Device {
String tracePath = null; String tracePath = null;
bool isComplete = false; bool isComplete = false;
while (!isComplete) { while (!isComplete) {
String logs = runCheckedSync(adbCommandForDevice(['logcat', '-d', '-T', beforeStop])); String logs = runCheckedSync(adbCommandForDevice(<String>['logcat', '-d', '-T', beforeStop]));
Match fileMatch = traceRegExp.firstMatch(logs); Match fileMatch = traceRegExp.firstMatch(logs);
if (fileMatch != null && fileMatch[1] != null) { if (fileMatch != null && fileMatch[1] != null) {
tracePath = fileMatch[1]; tracePath = fileMatch[1];
...@@ -430,7 +415,7 @@ class AndroidDevice extends Device { ...@@ -430,7 +415,7 @@ class AndroidDevice extends Device {
return null; return null;
} }
bool isConnected() => _connected != null ? _connected : _hasValidAndroid; bool isConnected() => _connected ?? _hasValidAndroid;
void setConnected(bool value) { void setConnected(bool value) {
_connected = value; _connected = value;
...@@ -444,13 +429,13 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) { ...@@ -444,13 +429,13 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
String adbPath = (mockAndroid != null) ? mockAndroid.adbPath : getAdbPath(); String adbPath = (mockAndroid != null) ? mockAndroid.adbPath : getAdbPath();
try { try {
runCheckedSync([adbPath, 'version']); runCheckedSync(<String>[adbPath, 'version']);
} catch (e) { } catch (e) {
printError('Unable to find adb. Is "adb" in your path?'); printError('Unable to find adb. Is "adb" in your path?');
return devices; return devices;
} }
List<String> output = runSync([adbPath, 'devices', '-l']).trim().split('\n'); List<String> output = runSync(<String>[adbPath, 'devices', '-l']).trim().split('\n');
// 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper // 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper
RegExp deviceRegex1 = new RegExp( RegExp deviceRegex1 = new RegExp(
...@@ -461,7 +446,7 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) { ...@@ -461,7 +446,7 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
RegExp unauthorizedRegex = new RegExp(r'^(\S+)\s+unauthorized\s+\S+$'); RegExp unauthorizedRegex = new RegExp(r'^(\S+)\s+unauthorized\s+\S+$');
RegExp offlineRegex = new RegExp(r'^(\S+)\s+offline\s+\S+$'); RegExp offlineRegex = new RegExp(r'^(\S+)\s+offline\s+\S+$');
// Skip first line, which is always 'List of devices attached'. // Skip the first line, which is always 'List of devices attached'.
for (String line in output.skip(1)) { for (String line in output.skip(1)) {
// Skip lines like: // Skip lines like:
// * daemon not running. starting it now on port 5037 * // * daemon not running. starting it now on port 5037 *
...@@ -484,15 +469,16 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) { ...@@ -484,15 +469,16 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
modelID = modelID.replaceAll('_', ' '); modelID = modelID.replaceAll('_', ' ');
devices.add(new AndroidDevice( devices.add(new AndroidDevice(
id: deviceID, deviceID,
productID: productID, productID: productID,
modelID: modelID, modelID: modelID,
deviceCodeName: deviceCodeName deviceCodeName: deviceCodeName,
connected: true
)); ));
} else if (deviceRegex2.hasMatch(line)) { } else if (deviceRegex2.hasMatch(line)) {
Match match = deviceRegex2.firstMatch(line); Match match = deviceRegex2.firstMatch(line);
String deviceID = match[1]; String deviceID = match[1];
devices.add(new AndroidDevice(id: deviceID)); devices.add(new AndroidDevice(deviceID, connected: true));
} else if (unauthorizedRegex.hasMatch(line)) { } else if (unauthorizedRegex.hasMatch(line)) {
Match match = unauthorizedRegex.firstMatch(line); Match match = unauthorizedRegex.firstMatch(line);
String deviceID = match[1]; String deviceID = match[1];
......
...@@ -366,7 +366,7 @@ int _buildApk( ...@@ -366,7 +366,7 @@ int _buildApk(
ensureDirectoryExists(finalApk.path); ensureDirectoryExists(finalApk.path);
builder.align(unalignedApk, finalApk); builder.align(unalignedApk, finalApk);
printStatus('APK generated: ${finalApk.path}'); printStatus('Generated APK to ${finalApk.path}.');
return 0; return 0;
} finally { } finally {
...@@ -520,7 +520,7 @@ Future<ApplicationPackageStore> buildAll( ...@@ -520,7 +520,7 @@ Future<ApplicationPackageStore> buildAll(
// TODO(mpcomplete): Temporary hack. We only support the apk builder atm. // TODO(mpcomplete): Temporary hack. We only support the apk builder atm.
if (package == applicationPackages.android) { if (package == applicationPackages.android) {
if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) { if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) {
printStatus('Using pre-built SkyShell.apk'); printStatus('Using pre-built SkyShell.apk.');
continue; continue;
} }
......
...@@ -362,7 +362,7 @@ class AndroidDeviceDiscovery { ...@@ -362,7 +362,7 @@ class AndroidDeviceDiscovery {
if (androidDevice == null) { if (androidDevice == null) {
// device added // device added
androidDevice = new AndroidDevice( androidDevice = new AndroidDevice(
id: device.id, device.id,
productID: device.productID, productID: device.productID,
modelID: device.modelID, modelID: device.modelID,
deviceCodeName: device.deviceCodeName, deviceCodeName: device.deviceCodeName,
...@@ -385,11 +385,6 @@ class AndroidDeviceDiscovery { ...@@ -385,11 +385,6 @@ class AndroidDeviceDiscovery {
for (AndroidDevice device in currentDevices) { for (AndroidDevice device in currentDevices) {
_devices.remove(device.id); _devices.remove(device.id);
// I don't know the purpose of this cache or if it's a good idea. We should
// probably have a DeviceManager singleton class to coordinate known devices
// and different device discovery mechanisms.
Device.removeFromCache(device.id);
removedController.add(device); removedController.add(device);
} }
} }
...@@ -424,7 +419,7 @@ class IOSSimulatorDeviceDiscovery { ...@@ -424,7 +419,7 @@ class IOSSimulatorDeviceDiscovery {
if (androidDevice == null) { if (androidDevice == null) {
// device added // device added
androidDevice = new IOSSimulator(id: device.udid, name: device.name); androidDevice = new IOSSimulator(device.udid, name: device.name);
_devices[androidDevice.id] = androidDevice; _devices[androidDevice.id] = androidDevice;
addedController.add(androidDevice); addedController.add(androidDevice);
} else { } else {
...@@ -436,8 +431,6 @@ class IOSSimulatorDeviceDiscovery { ...@@ -436,8 +431,6 @@ class IOSSimulatorDeviceDiscovery {
for (IOSSimulator device in currentDevices) { for (IOSSimulator device in currentDevices) {
_devices.remove(device.id); _devices.remove(device.id);
Device.removeFromCache(device.id);
removedController.add(device); removedController.add(device);
} }
} }
......
...@@ -66,18 +66,9 @@ abstract class DeviceDiscovery { ...@@ -66,18 +66,9 @@ abstract class DeviceDiscovery {
} }
abstract class Device { abstract class Device {
final String id; Device(this.id);
static Map<String, Device> _deviceCache = {};
static Device unique(String id, Device constructor(String id)) {
return _deviceCache.putIfAbsent(id, () => constructor(id));
}
static void removeFromCache(String id) {
_deviceCache.remove(id);
}
Device.fromId(this.id); final String id;
String get name; String get name;
...@@ -133,6 +124,12 @@ abstract class DeviceLogReader { ...@@ -133,6 +124,12 @@ abstract class DeviceLogReader {
// TODO(devoncarew): Unify this with [DeviceManager]. // TODO(devoncarew): Unify this with [DeviceManager].
class DeviceStore { class DeviceStore {
DeviceStore({
this.android,
this.iOS,
this.iOSSimulator
});
final AndroidDevice android; final AndroidDevice android;
final IOSDevice iOS; final IOSDevice iOS;
final IOSSimulator iOSSimulator; final IOSSimulator iOSSimulator;
...@@ -148,12 +145,6 @@ class DeviceStore { ...@@ -148,12 +145,6 @@ class DeviceStore {
return result; return result;
} }
DeviceStore({
this.android,
this.iOS,
this.iOSSimulator
});
static Device _deviceForConfig(BuildConfiguration config, List<Device> devices) { static Device _deviceForConfig(BuildConfiguration config, List<Device> devices) {
Device device = null; Device device = null;
...@@ -194,10 +185,6 @@ class DeviceStore { ...@@ -194,10 +185,6 @@ class DeviceStore {
case TargetPlatform.iOSSimulator: case TargetPlatform.iOSSimulator:
assert(iOSSimulator == null); assert(iOSSimulator == null);
iOSSimulator = _deviceForConfig(config, IOSSimulator.getAttachedDevices()); iOSSimulator = _deviceForConfig(config, IOSSimulator.getAttachedDevices());
if (iOSSimulator == null) {
// Creates a simulator with the default identifier
iOSSimulator = new IOSSimulator();
}
break; break;
case TargetPlatform.mac: case TargetPlatform.mac:
case TargetPlatform.linux: case TargetPlatform.linux:
......
...@@ -33,8 +33,8 @@ Map<String, double> _kIconDensities = { ...@@ -33,8 +33,8 @@ Map<String, double> _kIconDensities = {
'xxhdpi' : 3.0, 'xxhdpi' : 3.0,
'xxxhdpi' : 4.0 'xxxhdpi' : 4.0
}; };
const List<String> _kThemes = const ['white', 'black']; const List<String> _kThemes = const <String>['white', 'black'];
const List<int> _kSizes = const [18, 24, 36, 48]; const List<int> _kSizes = const <int>[18, 24, 36, 48];
class _Asset { class _Asset {
final String source; final String source;
......
...@@ -47,7 +47,19 @@ class IOSSimulatorDiscovery extends DeviceDiscovery { ...@@ -47,7 +47,19 @@ class IOSSimulatorDiscovery extends DeviceDiscovery {
} }
class IOSDevice extends Device { class IOSDevice extends Device {
static final String defaultDeviceID = 'default_ios_id'; IOSDevice(String id, { this.name }) : super(id) {
_installerPath = _checkForCommand('ideviceinstaller');
_listerPath = _checkForCommand('idevice_id');
_informerPath = _checkForCommand('ideviceinfo');
_debuggerPath = _checkForCommand('idevicedebug');
_loggerPath = _checkForCommand('idevicesyslog');
_pusherPath = _checkForCommand(
'ios-deploy',
'To copy files to iOS devices, please install ios-deploy. '
'You can do this using homebrew as follows:\n'
'\$ brew tap flutter/flutter\n'
'\$ brew install ios-deploy');
}
String _installerPath; String _installerPath;
String get installerPath => _installerPath; String get installerPath => _installerPath;
...@@ -67,50 +79,25 @@ class IOSDevice extends Device { ...@@ -67,50 +79,25 @@ class IOSDevice extends Device {
String _pusherPath; String _pusherPath;
String get pusherPath => _pusherPath; String get pusherPath => _pusherPath;
String _name; final String name;
String get name => _name;
factory IOSDevice({String id, String name}) {
IOSDevice device = Device.unique(id ?? defaultDeviceID, (String id) => new IOSDevice.fromId(id));
device._name = name;
return device;
}
IOSDevice.fromId(String id) : super.fromId(id) {
_installerPath = _checkForCommand('ideviceinstaller');
_listerPath = _checkForCommand('idevice_id');
_informerPath = _checkForCommand('ideviceinfo');
_debuggerPath = _checkForCommand('idevicedebug');
_loggerPath = _checkForCommand('idevicesyslog');
_pusherPath = _checkForCommand(
'ios-deploy',
'To copy files to iOS devices, please install ios-deploy. '
'You can do this using homebrew as follows:\n'
'\$ brew tap flutter/flutter\n'
'\$ brew install ios-deploy');
}
static List<IOSDevice> getAttachedDevices([IOSDevice mockIOS]) { static List<IOSDevice> getAttachedDevices([IOSDevice mockIOS]) {
List<IOSDevice> devices = []; List<IOSDevice> devices = [];
for (String id in _getAttachedDeviceIDs(mockIOS)) { for (String id in _getAttachedDeviceIDs(mockIOS)) {
String name = _getDeviceName(id, mockIOS); String name = _getDeviceName(id, mockIOS);
devices.add(new IOSDevice(id: id, name: name)); devices.add(new IOSDevice(id, name: name));
} }
return devices; return devices;
} }
static Iterable<String> _getAttachedDeviceIDs([IOSDevice mockIOS]) { static Iterable<String> _getAttachedDeviceIDs([IOSDevice mockIOS]) {
String listerPath = String listerPath = (mockIOS != null) ? mockIOS.listerPath : _checkForCommand('idevice_id');
(mockIOS != null) ? mockIOS.listerPath : _checkForCommand('idevice_id');
String output;
try { try {
output = runSync([listerPath, '-l']); String output = runSync([listerPath, '-l']);
return output.trim().split('\n').where((String s) => s != null && s.isNotEmpty);
} catch (e) { } catch (e) {
return []; return <String>[];
} }
return output.trim()
.split('\n')
.where((String s) => s != null && s.length > 0);
} }
static String _getDeviceName(String deviceID, [IOSDevice mockIOS]) { static String _getDeviceName(String deviceID, [IOSDevice mockIOS]) {
...@@ -142,11 +129,7 @@ class IOSDevice extends Device { ...@@ -142,11 +129,7 @@ class IOSDevice extends Device {
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
try { try {
if (id == defaultDeviceID) { runCheckedSync([installerPath, '-i', app.localPath]);
runCheckedSync([installerPath, '-i', app.localPath]);
} else {
runCheckedSync([installerPath, '-u', id, '-i', app.localPath]);
}
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
...@@ -155,15 +138,7 @@ class IOSDevice extends Device { ...@@ -155,15 +138,7 @@ class IOSDevice extends Device {
} }
@override @override
bool isConnected() { bool isConnected() => _getAttachedDeviceIDs().contains(id);
Iterable<String> ids = _getAttachedDeviceIDs();
for (String id in ids) {
if (id == this.id || this.id == defaultDeviceID) {
return true;
}
}
return false;
}
@override @override
bool isAppInstalled(ApplicationPackage app) { bool isAppInstalled(ApplicationPackage app) {
...@@ -238,7 +213,7 @@ class IOSDevice extends Device { ...@@ -238,7 +213,7 @@ class IOSDevice extends Device {
Future<bool> pushFile(ApplicationPackage app, String localFile, String targetFile) async { Future<bool> pushFile(ApplicationPackage app, String localFile, String targetFile) async {
if (Platform.isMacOS) { if (Platform.isMacOS) {
runSync([ runSync(<String>[
pusherPath, pusherPath,
'-t', '-t',
'1', '1',
...@@ -263,22 +238,15 @@ class IOSDevice extends Device { ...@@ -263,22 +238,15 @@ class IOSDevice extends Device {
} }
class IOSSimulator extends Device { class IOSSimulator extends Device {
factory IOSSimulator({String id, String name}) { IOSSimulator(String id, { this.name }) : super(id);
IOSSimulator device = Device.unique(id, (String id) => new IOSSimulator.fromId(id));
device._name = name;
return device;
}
static List<IOSSimulator> getAttachedDevices() { static List<IOSSimulator> getAttachedDevices() {
return SimControl.getConnectedDevices().map((SimDevice device) { return SimControl.getConnectedDevices().map((SimDevice device) {
return new IOSSimulator(id: device.udid, name: device.name); return new IOSSimulator(device.udid, name: device.name);
}).toList(); }).toList();
} }
IOSSimulator.fromId(String id) : super.fromId(id); final String name;
String _name;
String get name => _name;
String get xcrunPath => path.join('/usr', 'bin', 'xcrun'); String get xcrunPath => path.join('/usr', 'bin', 'xcrun');
...@@ -378,7 +346,7 @@ class IOSSimulator extends Device { ...@@ -378,7 +346,7 @@ class IOSSimulator extends Device {
ApplicationPackage app, String localFile, String targetFile) async { ApplicationPackage app, String localFile, String targetFile) async {
if (Platform.isMacOS) { if (Platform.isMacOS) {
String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app); String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app);
runCheckedSync(['cp', localFile, path.join(simulatorHomeDirectory, targetFile)]); runCheckedSync(<String>['cp', localFile, path.join(simulatorHomeDirectory, targetFile)]);
return true; return true;
} }
return false; return false;
...@@ -413,7 +381,7 @@ class _IOSDeviceLogReader extends DeviceLogReader { ...@@ -413,7 +381,7 @@ class _IOSDeviceLogReader extends DeviceLogReader {
return 2; return 2;
return await runCommandAndStreamOutput( return await runCommandAndStreamOutput(
[device.loggerPath], <String>[device.loggerPath],
prefix: '[$name] ', prefix: '[$name] ',
filter: new RegExp(r'(FlutterRunner|flutter.runner.Runner)') filter: new RegExp(r'(FlutterRunner|flutter.runner.Runner)')
); );
...@@ -512,7 +480,7 @@ bool _checkXcodeVersion() { ...@@ -512,7 +480,7 @@ bool _checkXcodeVersion() {
if (!Platform.isMacOS) if (!Platform.isMacOS)
return false; return false;
try { try {
String version = runCheckedSync(['xcodebuild', '-version']); String version = runCheckedSync(<String>['xcodebuild', '-version']);
Match match = _xcodeVersionRegExp.firstMatch(version); Match match = _xcodeVersionRegExp.firstMatch(version);
if (int.parse(match[1]) < 7) { if (int.parse(match[1]) < 7) {
printError('Found "${match[0]}". $_xcodeRequirement'); printError('Found "${match[0]}". $_xcodeRequirement');
...@@ -534,12 +502,12 @@ Future<bool> _buildIOSXcodeProject(ApplicationPackage app, bool isDevice) async ...@@ -534,12 +502,12 @@ Future<bool> _buildIOSXcodeProject(ApplicationPackage app, bool isDevice) async
if (!_checkXcodeVersion()) if (!_checkXcodeVersion())
return false; return false;
List<String> commands = [ List<String> commands = <String>[
'/usr/bin/env', 'xcrun', 'xcodebuild', '-target', 'Runner', '-configuration', 'Release' '/usr/bin/env', 'xcrun', 'xcodebuild', '-target', 'Runner', '-configuration', 'Release'
]; ];
if (!isDevice) { if (!isDevice) {
commands.addAll(['-sdk', 'iphonesimulator']); commands.addAll(<String>['-sdk', 'iphonesimulator']);
} }
try { try {
......
...@@ -9,22 +9,10 @@ main() => defineTests(); ...@@ -9,22 +9,10 @@ main() => defineTests();
defineTests() { defineTests() {
group('android_device', () { group('android_device', () {
test('uses the correct default ID', () {
AndroidDevice android = new AndroidDevice();
expect(android.id, equals(AndroidDevice.defaultDeviceID));
});
test('stores the requested id', () { test('stores the requested id', () {
String deviceId = '1234'; String deviceId = '1234';
AndroidDevice android = new AndroidDevice(id: deviceId); AndroidDevice device = new AndroidDevice(deviceId);
expect(android.id, equals(deviceId)); expect(device.id, equals(deviceId));
});
test('correctly creates only one of each requested device id', () {
String deviceID = '1234';
AndroidDevice a1 = new AndroidDevice(id: deviceID);
AndroidDevice a2 = new AndroidDevice(id: deviceID);
expect(a1, equals(a2));
}); });
}); });
} }
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