Add a flag that selects which Android device ID is the target for Flutter commands
This commit is contained in:
@@ -37,15 +37,19 @@ HostPlatform getCurrentHostPlatform() {
|
||||
}
|
||||
|
||||
class BuildConfiguration {
|
||||
BuildConfiguration.prebuilt({ this.hostPlatform, this.targetPlatform })
|
||||
: type = BuildType.prebuilt, buildDir = null;
|
||||
BuildConfiguration.prebuilt({
|
||||
this.hostPlatform,
|
||||
this.targetPlatform,
|
||||
this.deviceId
|
||||
}) : type = BuildType.prebuilt, buildDir = null;
|
||||
|
||||
BuildConfiguration.local({
|
||||
this.type,
|
||||
this.hostPlatform,
|
||||
this.targetPlatform,
|
||||
String enginePath,
|
||||
String buildPath
|
||||
String buildPath,
|
||||
this.deviceId
|
||||
}) : buildDir = path.normalize(path.join(enginePath, buildPath)) {
|
||||
assert(type == BuildType.debug || type == BuildType.release);
|
||||
}
|
||||
@@ -54,4 +58,5 @@ class BuildConfiguration {
|
||||
final HostPlatform hostPlatform;
|
||||
final TargetPlatform targetPlatform;
|
||||
final String buildDir;
|
||||
final String deviceId;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class FlutterCommandRunner extends CommandRunner {
|
||||
'shell commands executed.');
|
||||
argParser.addOption('package-root',
|
||||
help: 'Path to your packages directory.', defaultsTo: 'packages');
|
||||
argParser.addOption('android-device-id',
|
||||
help: 'Serial number of the target Android device.');
|
||||
|
||||
argParser.addSeparator('Local build selection options:');
|
||||
argParser.addFlag('debug',
|
||||
@@ -143,7 +145,10 @@ class FlutterCommandRunner extends CommandRunner {
|
||||
|
||||
if (enginePath == null) {
|
||||
configs.add(new BuildConfiguration.prebuilt(
|
||||
hostPlatform: hostPlatform, targetPlatform: TargetPlatform.android));
|
||||
hostPlatform: hostPlatform,
|
||||
targetPlatform: TargetPlatform.android,
|
||||
deviceId: globalResults['android-device-id']
|
||||
));
|
||||
} else {
|
||||
if (!FileSystemEntity.isDirectorySync(enginePath))
|
||||
_logging.warning('$enginePath is not a valid directory');
|
||||
@@ -157,7 +162,8 @@ class FlutterCommandRunner extends CommandRunner {
|
||||
hostPlatform: hostPlatform,
|
||||
targetPlatform: TargetPlatform.android,
|
||||
enginePath: enginePath,
|
||||
buildPath: globalResults['android-debug-build-path']
|
||||
buildPath: globalResults['android-debug-build-path'],
|
||||
deviceId: globalResults['android-device-id']
|
||||
));
|
||||
|
||||
if (Platform.isMacOS) {
|
||||
@@ -185,7 +191,8 @@ class FlutterCommandRunner extends CommandRunner {
|
||||
hostPlatform: hostPlatform,
|
||||
targetPlatform: TargetPlatform.android,
|
||||
enginePath: enginePath,
|
||||
buildPath: globalResults['android-release-build-path']
|
||||
buildPath: globalResults['android-release-build-path'],
|
||||
deviceId: globalResults['android-device-id']
|
||||
));
|
||||
|
||||
if (Platform.isMacOS) {
|
||||
|
||||
@@ -603,6 +603,15 @@ class AndroidDevice extends Device {
|
||||
}
|
||||
}
|
||||
|
||||
List<String> adbCommandForDevice(List<String> args) {
|
||||
List<String> result = <String>[adbPath];
|
||||
if (id != defaultDeviceID) {
|
||||
result.addAll(['-s', id]);
|
||||
}
|
||||
result.addAll(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _isValidAdbVersion(String adbVersion) {
|
||||
// Sample output: 'Android Debug Bridge version 1.0.31'
|
||||
Match versionFields =
|
||||
@@ -655,9 +664,9 @@ class AndroidDevice extends Device {
|
||||
// output lines like this, which we want to ignore:
|
||||
// adb server is out of date. killing..
|
||||
// * daemon started successfully *
|
||||
runCheckedSync([adbPath, 'start-server']);
|
||||
runCheckedSync(adbCommandForDevice(['start-server']));
|
||||
|
||||
String ready = runSync([adbPath, 'shell', 'echo', 'ready']);
|
||||
String ready = runSync(adbCommandForDevice(['shell', 'echo', 'ready']));
|
||||
if (ready.trim() != 'ready') {
|
||||
_logging.info('Android device not found.');
|
||||
return false;
|
||||
@@ -665,7 +674,7 @@ class AndroidDevice extends Device {
|
||||
|
||||
// Sample output: '22'
|
||||
String sdkVersion =
|
||||
runCheckedSync([adbPath, 'shell', 'getprop', 'ro.build.version.sdk'])
|
||||
runCheckedSync(adbCommandForDevice(['shell', 'getprop', 'ro.build.version.sdk']))
|
||||
.trimRight();
|
||||
|
||||
int sdkVersionParsed =
|
||||
@@ -699,7 +708,7 @@ class AndroidDevice extends Device {
|
||||
}
|
||||
|
||||
String _getDeviceApkSha1(ApplicationPackage app) {
|
||||
return runCheckedSync([adbPath, 'shell', 'cat', _getDeviceSha1Path(app)]);
|
||||
return runCheckedSync(adbCommandForDevice(['shell', 'cat', _getDeviceSha1Path(app)]));
|
||||
}
|
||||
|
||||
String _getSourceSha1(ApplicationPackage app) {
|
||||
@@ -721,7 +730,7 @@ class AndroidDevice extends Device {
|
||||
if (!isConnected()) {
|
||||
return false;
|
||||
}
|
||||
if (runCheckedSync([adbPath, 'shell', 'pm', 'path', app.id]) ==
|
||||
if (runCheckedSync(adbCommandForDevice(['shell', 'pm', 'path', app.id])) ==
|
||||
'') {
|
||||
_logging.info(
|
||||
'TODO(iansf): move this log to the caller. ${app.name} is not on the device. Installing now...');
|
||||
@@ -747,16 +756,16 @@ class AndroidDevice extends Device {
|
||||
}
|
||||
|
||||
print('Installing ${app.name} on device.');
|
||||
runCheckedSync([adbPath, 'install', '-r', app.localPath]);
|
||||
runCheckedSync([adbPath, 'shell', 'run-as', app.id, 'chmod', '777', _getDeviceDataPath(app)]);
|
||||
runCheckedSync([adbPath, 'shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app)]);
|
||||
runCheckedSync(adbCommandForDevice(['install', '-r', app.localPath]));
|
||||
runCheckedSync(adbCommandForDevice(['shell', 'run-as', app.id, 'chmod', '777', _getDeviceDataPath(app)]));
|
||||
runCheckedSync(adbCommandForDevice(['shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app)]));
|
||||
return true;
|
||||
}
|
||||
|
||||
void _forwardObservatoryPort() {
|
||||
// Set up port forwarding for observatory.
|
||||
String portString = 'tcp:$_observatoryPort';
|
||||
runCheckedSync([adbPath, 'forward', portString, portString]);
|
||||
runCheckedSync(adbCommandForDevice(['forward', portString, portString]));
|
||||
}
|
||||
|
||||
bool startBundle(AndroidApk apk, String bundlePath, bool poke, bool checked) {
|
||||
@@ -770,14 +779,13 @@ class AndroidDevice extends Device {
|
||||
|
||||
String deviceTmpPath = '/data/local/tmp/dev.flx';
|
||||
String deviceBundlePath = _getDeviceBundlePath(apk);
|
||||
runCheckedSync([adbPath, 'push', bundlePath, deviceTmpPath]);
|
||||
runCheckedSync([adbPath, 'shell', 'mv', deviceTmpPath, deviceBundlePath]);
|
||||
List<String> cmd = [
|
||||
adbPath,
|
||||
runCheckedSync(adbCommandForDevice(['push', bundlePath, deviceTmpPath]));
|
||||
runCheckedSync(adbCommandForDevice(['shell', 'mv', deviceTmpPath, deviceBundlePath]));
|
||||
List<String> cmd = adbCommandForDevice([
|
||||
'shell', 'am', 'start',
|
||||
'-a', 'android.intent.action.RUN',
|
||||
'-d', deviceBundlePath,
|
||||
];
|
||||
]);
|
||||
if (checked)
|
||||
cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
|
||||
cmd.add(apk.launchActivity);
|
||||
@@ -821,7 +829,7 @@ class AndroidDevice extends Device {
|
||||
// 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]);
|
||||
runCheckedSync(adbCommandForDevice(['reverse', serverPortString, serverPortString]));
|
||||
}
|
||||
|
||||
String relativeDartMain = _convertToURL(path.relative(mainDart, from: serverRoot));
|
||||
@@ -830,12 +838,11 @@ class AndroidDevice extends Device {
|
||||
url += '?rand=${new Random().nextDouble()}';
|
||||
|
||||
// Actually launch the app on Android.
|
||||
List<String> cmd = [
|
||||
adbPath,
|
||||
List<String> cmd = adbCommandForDevice([
|
||||
'shell', 'am', 'start',
|
||||
'-a', 'android.intent.action.VIEW',
|
||||
'-d', url,
|
||||
];
|
||||
]);
|
||||
if (checked)
|
||||
cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
|
||||
cmd.add(apk.launchActivity);
|
||||
@@ -854,9 +861,9 @@ class AndroidDevice extends Device {
|
||||
final AndroidApk apk = app;
|
||||
|
||||
// Turn off reverse port forwarding
|
||||
runSync([adbPath, 'reverse', '--remove', 'tcp:$_serverPort']);
|
||||
runSync(adbCommandForDevice(['reverse', '--remove', 'tcp:$_serverPort']));
|
||||
// Stop the app
|
||||
runSync([adbPath, 'shell', 'am', 'force-stop', apk.id]);
|
||||
runSync(adbCommandForDevice(['shell', 'am', 'force-stop', apk.id]));
|
||||
|
||||
// Kill the server
|
||||
osUtils.killTcpPortListeners(_serverPort);
|
||||
@@ -868,7 +875,7 @@ class AndroidDevice extends Device {
|
||||
TargetPlatform get platform => TargetPlatform.android;
|
||||
|
||||
void clearLogs() {
|
||||
runSync([adbPath, 'logcat', '-c']);
|
||||
runSync(adbCommandForDevice(['logcat', '-c']));
|
||||
}
|
||||
|
||||
Future<int> logs({bool clear: false}) async {
|
||||
@@ -880,8 +887,7 @@ class AndroidDevice extends Device {
|
||||
clearLogs();
|
||||
}
|
||||
|
||||
return runCommandAndStreamOutput([
|
||||
adbPath,
|
||||
return runCommandAndStreamOutput(adbCommandForDevice([
|
||||
'logcat',
|
||||
'-v',
|
||||
'tag', // Only log the tag and the message
|
||||
@@ -890,30 +896,28 @@ class AndroidDevice extends Device {
|
||||
'chromium:D',
|
||||
'ActivityManager:W',
|
||||
'*:F',
|
||||
], prefix: 'android: ');
|
||||
]), prefix: 'android: ');
|
||||
}
|
||||
|
||||
void startTracing(AndroidApk apk) {
|
||||
runCheckedSync([
|
||||
adbPath,
|
||||
runCheckedSync(adbCommandForDevice([
|
||||
'shell',
|
||||
'am',
|
||||
'broadcast',
|
||||
'-a',
|
||||
'${apk.id}.TRACING_START'
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
String stopTracing(AndroidApk apk) {
|
||||
clearLogs();
|
||||
runCheckedSync([
|
||||
adbPath,
|
||||
runCheckedSync(adbCommandForDevice([
|
||||
'shell',
|
||||
'am',
|
||||
'broadcast',
|
||||
'-a',
|
||||
'${apk.id}.TRACING_STOP'
|
||||
]);
|
||||
]));
|
||||
|
||||
RegExp traceRegExp = new RegExp(r'Saving trace to (\S+)', multiLine: true);
|
||||
RegExp completeRegExp = new RegExp(r'Trace complete', multiLine: true);
|
||||
@@ -921,7 +925,7 @@ class AndroidDevice extends Device {
|
||||
String tracePath = null;
|
||||
bool isComplete = false;
|
||||
while (!isComplete) {
|
||||
String logs = runSync([adbPath, 'logcat', '-d']);
|
||||
String logs = runSync(adbCommandForDevice(['logcat', '-d']));
|
||||
Match fileMatch = traceRegExp.firstMatch(logs);
|
||||
if (fileMatch[1] != null) {
|
||||
tracePath = fileMatch[1];
|
||||
@@ -930,9 +934,9 @@ class AndroidDevice extends Device {
|
||||
}
|
||||
|
||||
if (tracePath != null) {
|
||||
runSync([adbPath, 'shell', 'run-as', apk.id, 'chmod', '777', tracePath]);
|
||||
runSync([adbPath, 'pull', tracePath]);
|
||||
runSync([adbPath, 'shell', 'rm', tracePath]);
|
||||
runSync(adbCommandForDevice(['shell', 'run-as', apk.id, 'chmod', '777', tracePath]));
|
||||
runSync(adbCommandForDevice(['pull', tracePath]));
|
||||
runSync(adbCommandForDevice(['shell', 'rm', tracePath]));
|
||||
return path.basename(tracePath);
|
||||
}
|
||||
_logging.warning('No trace file detected. '
|
||||
@@ -975,7 +979,19 @@ class DeviceStore {
|
||||
switch (config.targetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
assert(android == null);
|
||||
android = new AndroidDevice();
|
||||
List<AndroidDevice> androidDevices = AndroidDevice.getAttachedDevices();
|
||||
if (config.deviceId != null) {
|
||||
android = androidDevices.firstWhere(
|
||||
(AndroidDevice dev) => (dev.id == config.deviceId),
|
||||
orElse: () => null);
|
||||
if (android == null) {
|
||||
print('Warning: Device ID ${config.deviceId} not found');
|
||||
}
|
||||
} else if (androidDevices.length == 1) {
|
||||
android = androidDevices[0];
|
||||
} else if (androidDevices.length > 1) {
|
||||
print('Warning: Multiple Android devices are connected, but no device ID was specified.');
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.iOS:
|
||||
assert(iOS == null);
|
||||
|
||||
Reference in New Issue
Block a user