// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import '../android/android_device.dart'; import '../application_package.dart'; import '../base/common.dart'; import '../base/io.dart'; import '../device.dart'; import '../globals.dart' as globals; import '../runner/flutter_command.dart'; class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { InstallCommand() { requiresPubspecYaml(); usesDeviceUserOption(); usesDeviceTimeoutOption(); argParser.addFlag('uninstall-only', help: 'Uninstall the app if already on the device. Skip install.', ); } @override final String name = 'install'; @override final String description = 'Install a Flutter app on an attached device.'; @override final String category = FlutterCommandCategory.tools; Device? device; bool get uninstallOnly => boolArg('uninstall-only'); String? get userIdentifier => stringArg(FlutterOptions.kDeviceUser); @override Future<void> validateCommand() async { await super.validateCommand(); device = await findTargetDevice(); if (device == null) { throwToolExit('No target device found'); } if (userIdentifier != null && device is! AndroidDevice) { throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android'); } } @override Future<FlutterCommandResult> runCommand() async { final Device targetDevice = device!; final ApplicationPackage? package = await applicationPackages?.getPackageForPlatform( await targetDevice.targetPlatform, ); if (package == null) { throwToolExit('Could not find or build package'); } if (uninstallOnly) { await _uninstallApp(package, targetDevice); } else { await _installApp(package, targetDevice); } return FlutterCommandResult.success(); } Future<void> _uninstallApp(ApplicationPackage package, Device device) async { if (await device.isAppInstalled(package, userIdentifier: userIdentifier)) { globals.printStatus('Uninstalling $package from $device...'); if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) { globals.printError('Uninstalling old version failed'); } } else { globals.printStatus('$package not found on $device, skipping uninstall'); } } Future<void> _installApp(ApplicationPackage package, Device device) async { globals.printStatus('Installing $package to $device...'); if (!await installApp(device, package, userIdentifier: userIdentifier)) { throwToolExit('Install failed'); } } } Future<bool> installApp( Device device, ApplicationPackage package, { String? userIdentifier, bool uninstall = true }) async { if (package == null) { return false; } try { if (uninstall && await device.isAppInstalled(package, userIdentifier: userIdentifier)) { globals.printStatus('Uninstalling old version...'); if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) { globals.printWarning('Warning: uninstalling old version failed'); } } } on ProcessException catch (e) { globals.printError('Error accessing device ${device.id}:\n${e.message}'); } return device.installApp(package, userIdentifier: userIdentifier); }