mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Enable launching applications on the iOS device with observatory and diagnostics server connected. (#4424)
This commit is contained in:
parent
f92f71feb9
commit
9782d97faa
@ -307,10 +307,12 @@ class LaunchResult {
|
||||
}
|
||||
|
||||
class ForwardedPort {
|
||||
ForwardedPort(this.hostPort, this.devicePort);
|
||||
ForwardedPort(this.hostPort, this.devicePort) : context = null;
|
||||
ForwardedPort.withContext(this.hostPort, this.devicePort, this.context);
|
||||
|
||||
final int hostPort;
|
||||
final int devicePort;
|
||||
final dynamic context;
|
||||
|
||||
@override
|
||||
String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
|
||||
|
@ -12,6 +12,8 @@ import '../base/process.dart';
|
||||
import '../build_info.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart';
|
||||
import '../observatory.dart';
|
||||
import '../protocol_discovery.dart';
|
||||
import 'mac.dart';
|
||||
|
||||
const String _ideviceinstallerInstructions =
|
||||
@ -33,6 +35,7 @@ class IOSDevice extends Device {
|
||||
_installerPath = _checkForCommand('ideviceinstaller');
|
||||
_listerPath = _checkForCommand('idevice_id');
|
||||
_informerPath = _checkForCommand('ideviceinfo');
|
||||
_iproxyPath = _checkForCommand('iproxy');
|
||||
_debuggerPath = _checkForCommand('idevicedebug');
|
||||
_loggerPath = _checkForCommand('idevicesyslog');
|
||||
_pusherPath = _checkForCommand(
|
||||
@ -52,6 +55,9 @@ class IOSDevice extends Device {
|
||||
String _informerPath;
|
||||
String get informerPath => _informerPath;
|
||||
|
||||
String _iproxyPath;
|
||||
String get iproxyPath => _iproxyPath;
|
||||
|
||||
String _debuggerPath;
|
||||
String get debuggerPath => _debuggerPath;
|
||||
|
||||
@ -194,7 +200,20 @@ class IOSDevice extends Device {
|
||||
}
|
||||
|
||||
// Step 3: Attempt to install the application on the device.
|
||||
int installationResult = await runCommandAndStreamOutput(<String>[
|
||||
List<String> launchArguments = <String>[];
|
||||
|
||||
if (debuggingOptions.startPaused)
|
||||
launchArguments.add("--start-paused");
|
||||
|
||||
if (debuggingOptions.debuggingEnabled) {
|
||||
launchArguments.add("--enable-checked-mode");
|
||||
|
||||
// Note: We do NOT need to set the observatory port since this is going to
|
||||
// be setup on the device. Let it pick a port automatically. We will check
|
||||
// the port picked and scrape that later.
|
||||
}
|
||||
|
||||
List<String> launchCommand = <String>[
|
||||
'/usr/bin/env',
|
||||
'ios-deploy',
|
||||
'--id',
|
||||
@ -202,14 +221,109 @@ class IOSDevice extends Device {
|
||||
'--bundle',
|
||||
bundle.path,
|
||||
'--justlaunch',
|
||||
], trace: true);
|
||||
];
|
||||
|
||||
if (launchArguments.length > 0) {
|
||||
launchCommand.add('--args');
|
||||
launchCommand.add('"${launchArguments.join(" ")}"');
|
||||
}
|
||||
|
||||
int installationResult = -1;
|
||||
int localObsPort;
|
||||
int localDiagPort;
|
||||
|
||||
if (!debuggingOptions.debuggingEnabled || mode == BuildMode.release) {
|
||||
// If debugging is not enabled, just launch the application and continue.
|
||||
printTrace("Debugging is not enabled");
|
||||
installationResult = await runCommandAndStreamOutput(launchCommand, trace: true);
|
||||
} else {
|
||||
// Debugging is enabled, look for the observatory and diagnostic server
|
||||
// ports post launch.
|
||||
printTrace("Debugging is enabled, connecting to observatory and the diagnostic server");
|
||||
|
||||
Future<int> launch = runCommandAndStreamOutput(launchCommand, trace: true);
|
||||
|
||||
List<int> ports = await launch.then((int result) async {
|
||||
installationResult = result;
|
||||
|
||||
if (result != 0) {
|
||||
printTrace("Failed to launch the application on device.");
|
||||
return <int>[null, null];
|
||||
}
|
||||
|
||||
printTrace("Application launched on the device. Attempting to forward ports.");
|
||||
|
||||
return Future.wait(<Future<int>>[
|
||||
_acquireAndForwardPort(ProtocolDiscovery.kObservatoryService, debuggingOptions.observatoryPort),
|
||||
_acquireAndForwardPort(ProtocolDiscovery.kDiagnosticService, debuggingOptions.diagnosticPort),
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
printTrace("Local Observatory Port: ${ports[0]}");
|
||||
printTrace("Local Diagnostic Server Port: ${ports[1]}");
|
||||
|
||||
localObsPort = ports[0];
|
||||
localDiagPort = ports[1];
|
||||
}
|
||||
|
||||
if (installationResult != 0) {
|
||||
printError('Could not install ${bundle.path} on $id.');
|
||||
return new LaunchResult.failed();
|
||||
}
|
||||
|
||||
return new LaunchResult.succeeded();
|
||||
return new LaunchResult.succeeded(observatoryPort: localObsPort, diagnosticPort: localDiagPort);
|
||||
}
|
||||
|
||||
Future<int> _acquireAndForwardPort(String serviceName, int localPort) async {
|
||||
Duration stepTimeout = const Duration(seconds: 10);
|
||||
|
||||
Future<int> remote = new ProtocolDiscovery(logReader, serviceName).nextPort();
|
||||
|
||||
int remotePort = await remote.timeout(stepTimeout,
|
||||
onTimeout: () {
|
||||
printTrace("Timeout while attempting to retrieve remote port for $serviceName");
|
||||
return null;
|
||||
});
|
||||
|
||||
if (remotePort == null) {
|
||||
printTrace("Could not read port on device for $serviceName");
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((localPort == null) || (localPort == 0)) {
|
||||
localPort = await findAvailablePort();
|
||||
printTrace("Auto selected local port to $localPort");
|
||||
}
|
||||
|
||||
int forwardResult = await portForwarder.forward(remotePort,
|
||||
hostPort: localPort).timeout(stepTimeout, onTimeout: () {
|
||||
printTrace("Timeout while atempting to foward port for $serviceName");
|
||||
return null;
|
||||
});
|
||||
|
||||
if (forwardResult == null) {
|
||||
printTrace("Could not foward remote $serviceName port $remotePort to local port $localPort");
|
||||
return null;
|
||||
}
|
||||
|
||||
printTrace("Successfully forwarded remote $serviceName port $remotePort to $localPort.");
|
||||
return localPort;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> restartApp(
|
||||
ApplicationPackage package,
|
||||
LaunchResult result, {
|
||||
String mainPath,
|
||||
Observatory observatory
|
||||
}) async {
|
||||
return observatory.isolateReload(observatory.firstIsolateId).then((Response response) {
|
||||
return true;
|
||||
}).catchError((dynamic error) {
|
||||
printError('Error restarting app: $error');
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -306,11 +420,16 @@ class _IOSDeviceLogReader extends DeviceLogReader {
|
||||
});
|
||||
}
|
||||
|
||||
static final RegExp _runnerRegex = new RegExp(r'FlutterRunner');
|
||||
// Match for lines like "Runner[297] <Notice>: " in syslog.
|
||||
static final RegExp _runnerRegex = new RegExp(r'Runner\[[\d]+\] <[A-Za-z]+>: ');
|
||||
|
||||
void _onLine(String line) {
|
||||
if (_runnerRegex.hasMatch(line))
|
||||
_linesController.add(line);
|
||||
Match match = _runnerRegex.firstMatch(line);
|
||||
|
||||
if (match != null) {
|
||||
// Only display the log line after the initial device and executable information.
|
||||
_linesController.add(line.substring(match.end));
|
||||
}
|
||||
}
|
||||
|
||||
void _stop() {
|
||||
@ -319,16 +438,14 @@ class _IOSDeviceLogReader extends DeviceLogReader {
|
||||
}
|
||||
|
||||
class _IOSDevicePortForwarder extends DevicePortForwarder {
|
||||
_IOSDevicePortForwarder(this.device);
|
||||
_IOSDevicePortForwarder(this.device) : _forwardedPorts = new List<ForwardedPort>();
|
||||
|
||||
final IOSDevice device;
|
||||
|
||||
final List<ForwardedPort> _forwardedPorts;
|
||||
|
||||
@override
|
||||
List<ForwardedPort> get forwardedPorts {
|
||||
final List<ForwardedPort> ports = <ForwardedPort>[];
|
||||
// TODO(chinmaygarde): Implement.
|
||||
return ports;
|
||||
}
|
||||
List<ForwardedPort> get forwardedPorts => _forwardedPorts;
|
||||
|
||||
@override
|
||||
Future<int> forward(int devicePort, {int hostPort: null}) async {
|
||||
@ -336,12 +453,42 @@ class _IOSDevicePortForwarder extends DevicePortForwarder {
|
||||
// Auto select host port.
|
||||
hostPort = await findAvailablePort();
|
||||
}
|
||||
// TODO(chinmaygarde): Implement.
|
||||
return hostPort;
|
||||
|
||||
// Usage: iproxy LOCAL_TCP_PORT DEVICE_TCP_PORT UDID
|
||||
Process process = await runCommand(<String>[
|
||||
device.iproxyPath,
|
||||
hostPort.toString(),
|
||||
devicePort.toString(),
|
||||
device.id,
|
||||
]);
|
||||
|
||||
ForwardedPort forwardedPort = new ForwardedPort.withContext(hostPort,
|
||||
devicePort, process);
|
||||
|
||||
printTrace("Forwarded port $forwardedPort");
|
||||
|
||||
_forwardedPorts.add(forwardedPort);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Null> unforward(ForwardedPort forwardedPort) async {
|
||||
// TODO(chinmaygarde): Implement.
|
||||
if (!_forwardedPorts.remove(forwardedPort)) {
|
||||
// Not in list. Nothing to remove.
|
||||
return null;
|
||||
}
|
||||
|
||||
printTrace("Unforwarding port $forwardedPort");
|
||||
|
||||
Process process = forwardedPort.context;
|
||||
|
||||
if (process != null) {
|
||||
Process.killPid(process.pid);
|
||||
} else {
|
||||
printError("Forwarded port did not have a valid process");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user