Commit 51d4ab33 authored by Todd Volkert's avatar Todd Volkert

Fix install for iOS simulator, and add ability to uninstall (#4223)

parent 1a05b696
...@@ -232,6 +232,22 @@ class AndroidDevice extends Device { ...@@ -232,6 +232,22 @@ class AndroidDevice extends Device {
return true; return true;
} }
@override
bool uninstallApp(ApplicationPackage app) {
if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
return false;
String uninstallOut = runCheckedSync(adbCommandForDevice(<String>['uninstall', app.id]));
RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true);
String failure = failureExp.stringMatch(uninstallOut);
if (failure != null) {
printError('Package uninstall error: $failure');
return false;
}
return true;
}
Future<Null> _forwardPort(String service, int devicePort, int port) async { Future<Null> _forwardPort(String service, int devicePort, int port) async {
try { try {
// Set up port forwarding for observatory. // Set up port forwarding for observatory.
......
...@@ -274,6 +274,8 @@ Future<int> startApp(DriveCommand command) async { ...@@ -274,6 +274,8 @@ Future<int> startApp(DriveCommand command) async {
printTrace('Installing application package.'); printTrace('Installing application package.');
ApplicationPackage package = command.applicationPackages ApplicationPackage package = command.applicationPackages
.getPackageForPlatform(command.device.platform); .getPackageForPlatform(command.device.platform);
if (command.device.isAppInstalled(package))
command.device.uninstallApp(package);
command.device.installApp(package); command.device.installApp(package);
Map<String, dynamic> platformArgs = <String, dynamic>{}; Map<String, dynamic> platformArgs = <String, dynamic>{};
......
...@@ -34,8 +34,11 @@ bool installApp(Device device, ApplicationPackage package) { ...@@ -34,8 +34,11 @@ bool installApp(Device device, ApplicationPackage package) {
if (package == null) if (package == null)
return false; return false;
if (device.isAppInstalled(package)) if (device.isAppInstalled(package)) {
return true; printStatus('Uninstalling old version...');
if (!device.uninstallApp(package))
printError('Warning: uninstalling old version failed');
}
return device.installApp(package); return device.installApp(package);
} }
...@@ -149,9 +149,15 @@ abstract class Device { ...@@ -149,9 +149,15 @@ abstract class Device {
/// Whether it is an emulated device running on localhost. /// Whether it is an emulated device running on localhost.
bool get isLocalEmulator; bool get isLocalEmulator;
/// Check if a version of the given app is already installed
bool isAppInstalled(ApplicationPackage app);
/// Install an app package on the current device /// Install an app package on the current device
bool installApp(ApplicationPackage app); bool installApp(ApplicationPackage app);
/// Uninstall an app package from the current device
bool uninstallApp(ApplicationPackage app);
/// Check if the device is supported by Flutter /// Check if the device is supported by Flutter
bool isSupported(); bool isSupported();
...@@ -159,9 +165,6 @@ abstract class Device { ...@@ -159,9 +165,6 @@ abstract class Device {
// supported by Flutter, and, if not, why. // supported by Flutter, and, if not, why.
String supportMessage() => isSupported() ? "Supported" : "Unsupported"; String supportMessage() => isSupported() ? "Supported" : "Unsupported";
/// Check if the current version of the given app is already installed
bool isAppInstalled(ApplicationPackage app);
TargetPlatform get platform; TargetPlatform get platform;
/// Get the log reader for this device. /// Get the log reader for this device.
......
...@@ -124,11 +124,12 @@ class IOSDevice extends Device { ...@@ -124,11 +124,12 @@ class IOSDevice extends Device {
} }
@override @override
bool installApp(ApplicationPackage app) { bool isAppInstalled(ApplicationPackage app) {
try { try {
IOSApp iosApp = app; String apps = runCheckedSync(<String>[installerPath, '--list-apps']);
runCheckedSync(<String>[installerPath, '-i', iosApp.deviceBundlePath]); if (new RegExp(app.id, multiLine: true).hasMatch(apps)) {
return true; return true;
}
} catch (e) { } catch (e) {
return false; return false;
} }
...@@ -136,21 +137,35 @@ class IOSDevice extends Device { ...@@ -136,21 +137,35 @@ class IOSDevice extends Device {
} }
@override @override
bool isSupported() => true; bool installApp(ApplicationPackage app) {
IOSApp iosApp = app;
Directory bundle = new Directory(iosApp.deviceBundlePath);
if (!bundle.existsSync()) {
printError("Could not find application bundle at ${bundle.path}; have you run 'flutter build ios'?");
return false;
}
try {
runCheckedSync(<String>[installerPath, '-i', iosApp.deviceBundlePath]);
return true;
} catch (e) {
return false;
}
}
@override @override
bool isAppInstalled(ApplicationPackage app) { bool uninstallApp(ApplicationPackage app) {
try { try {
String apps = runCheckedSync(<String>[installerPath, '--list-apps']); runCheckedSync(<String>[installerPath, '-U', app.id]);
if (new RegExp(app.id, multiLine: true).hasMatch(apps)) { return true;
return true;
}
} catch (e) { } catch (e) {
return false; return false;
} }
return false;
} }
@override
bool isSupported() => true;
@override @override
Future<LaunchResult> startApp( Future<LaunchResult> startApp(
ApplicationPackage app, ApplicationPackage app,
...@@ -174,8 +189,7 @@ class IOSDevice extends Device { ...@@ -174,8 +189,7 @@ class IOSDevice extends Device {
// Step 2: Check that the application exists at the specified path. // Step 2: Check that the application exists at the specified path.
IOSApp iosApp = app; IOSApp iosApp = app;
Directory bundle = new Directory(iosApp.deviceBundlePath); Directory bundle = new Directory(iosApp.deviceBundlePath);
bool bundleExists = bundle.existsSync(); if (!bundle.existsSync()) {
if (!bundleExists) {
printError('Could not find the built application bundle at ${bundle.path}.'); printError('Could not find the built application bundle at ${bundle.path}.');
return new LaunchResult.failed(); return new LaunchResult.failed();
} }
......
...@@ -274,10 +274,24 @@ class SimControl { ...@@ -274,10 +274,24 @@ class SimControl {
bool _isAnyConnected() => getConnectedDevices().isNotEmpty; bool _isAnyConnected() => getConnectedDevices().isNotEmpty;
bool isInstalled(String appId) {
return exitsHappy(<String>[
_xcrunPath,
'simctl',
'get_app_container',
'booted',
appId,
]);
}
void install(String deviceId, String appPath) { void install(String deviceId, String appPath) {
runCheckedSync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]); runCheckedSync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]);
} }
void uninstall(String deviceId, String appId) {
runCheckedSync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]);
}
void launch(String deviceId, String appIdentifier, [List<String> launchArgs]) { void launch(String deviceId, String appIdentifier, [List<String> launchArgs]) {
List<String> args = <String>[_xcrunPath, 'simctl', 'launch', deviceId, appIdentifier]; List<String> args = <String>[_xcrunPath, 'simctl', 'launch', deviceId, appIdentifier];
if (launchArgs != null) if (launchArgs != null)
...@@ -361,6 +375,11 @@ class IOSSimulator extends Device { ...@@ -361,6 +375,11 @@ class IOSSimulator extends Device {
return path.join(simulatorPath, 'data'); return path.join(simulatorPath, 'data');
} }
@override
bool isAppInstalled(ApplicationPackage app) {
return SimControl.instance.isInstalled(app.id);
}
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
try { try {
...@@ -372,6 +391,16 @@ class IOSSimulator extends Device { ...@@ -372,6 +391,16 @@ class IOSSimulator extends Device {
} }
} }
@override
bool uninstallApp(ApplicationPackage app) {
try {
SimControl.instance.uninstall(id, app.id);
return true;
} catch (e) {
return false;
}
}
@override @override
bool isSupported() { bool isSupported() {
if (!Platform.isMacOS) { if (!Platform.isMacOS) {
...@@ -423,17 +452,6 @@ class IOSSimulator extends Device { ...@@ -423,17 +452,6 @@ class IOSSimulator extends Device {
return _supportMessage != null ? _supportMessage : "Unknown"; return _supportMessage != null ? _supportMessage : "Unknown";
} }
@override
bool isAppInstalled(ApplicationPackage app) {
try {
// TODO(tvolkert): This logic is wrong; simulatorHomeDirectory always exists
String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app);
return FileSystemEntity.isDirectorySync(simulatorHomeDirectory);
} catch (e) {
return false;
}
}
@override @override
Future<LaunchResult> startApp( Future<LaunchResult> startApp(
ApplicationPackage app, ApplicationPackage app,
...@@ -505,13 +523,7 @@ class IOSSimulator extends Device { ...@@ -505,13 +523,7 @@ class IOSSimulator extends Device {
} }
bool _applicationIsInstalledAndRunning(ApplicationPackage app) { bool _applicationIsInstalledAndRunning(ApplicationPackage app) {
bool isInstalled = exitsHappy(<String>[ bool isInstalled = isAppInstalled(app);
'xcrun',
'simctl',
'get_app_container',
'booted',
app.id,
]);
bool isRunning = exitsHappy(<String>[ bool isRunning = exitsHappy(<String>[
'/usr/bin/killall', '/usr/bin/killall',
......
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