| // 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. |
| |
| // @dart = 2.8 |
| |
| import 'dart:async'; |
| |
| import 'package:meta/meta.dart'; |
| import 'package:process/process.dart'; |
| |
| import '../application_package.dart'; |
| import '../base/file_system.dart'; |
| import '../base/io.dart'; |
| import '../base/logger.dart'; |
| import '../base/os.dart'; |
| import '../base/utils.dart'; |
| import '../build_info.dart'; |
| import '../desktop_device.dart'; |
| import '../device.dart'; |
| import '../device_port_forwarder.dart'; |
| import '../features.dart'; |
| import '../project.dart'; |
| import 'application_package.dart'; |
| import 'build_windows.dart'; |
| import 'uwptool.dart'; |
| import 'windows_workflow.dart'; |
| |
| /// A device that represents a desktop Windows target. |
| class WindowsDevice extends DesktopDevice { |
| WindowsDevice({ |
| @required ProcessManager processManager, |
| @required Logger logger, |
| @required FileSystem fileSystem, |
| @required OperatingSystemUtils operatingSystemUtils, |
| }) : super( |
| 'windows', |
| platformType: PlatformType.windows, |
| ephemeral: false, |
| processManager: processManager, |
| logger: logger, |
| fileSystem: fileSystem, |
| operatingSystemUtils: operatingSystemUtils, |
| ); |
| |
| @override |
| bool isSupported() => true; |
| |
| @override |
| String get name => 'Windows'; |
| |
| @override |
| Future<TargetPlatform> get targetPlatform async => TargetPlatform.windows_x64; |
| |
| @override |
| bool isSupportedForProject(FlutterProject flutterProject) { |
| return flutterProject.windows.existsSync(); |
| } |
| |
| @override |
| Future<void> buildForDevice( |
| covariant WindowsApp package, { |
| String mainPath, |
| BuildInfo buildInfo, |
| }) async { |
| await buildWindows( |
| FlutterProject.current().windows, |
| buildInfo, |
| target: mainPath, |
| ); |
| } |
| |
| @override |
| String executablePathForDevice(covariant WindowsApp package, BuildMode buildMode) { |
| return package.executable(buildMode); |
| } |
| } |
| |
| // A device that represents a desktop Windows UWP target. |
| class WindowsUWPDevice extends Device { |
| WindowsUWPDevice({ |
| @required ProcessManager processManager, |
| @required Logger logger, |
| @required FileSystem fileSystem, |
| @required OperatingSystemUtils operatingSystemUtils, |
| @required UwpTool uwptool, |
| }) : _logger = logger, |
| _processManager = processManager, |
| _operatingSystemUtils = operatingSystemUtils, |
| _fileSystem = fileSystem, |
| _uwptool = uwptool, |
| super( |
| 'winuwp', |
| platformType: PlatformType.windows, |
| ephemeral: false, |
| category: Category.desktop, |
| ); |
| |
| final ProcessManager _processManager; |
| final Logger _logger; |
| final FileSystem _fileSystem; |
| final OperatingSystemUtils _operatingSystemUtils; |
| final UwpTool _uwptool; |
| BuildMode _buildMode; |
| |
| int _processId; |
| |
| @override |
| bool isSupported() => true; |
| |
| @override |
| String get name => 'Windows (UWP)'; |
| |
| @override |
| Future<TargetPlatform> get targetPlatform async => TargetPlatform.windows_uwp_x64; |
| |
| @override |
| bool isSupportedForProject(FlutterProject flutterProject) { |
| return flutterProject.windowsUwp.existsSync(); |
| } |
| |
| @override |
| void clearLogs() { } |
| |
| @override |
| Future<void> dispose() async { } |
| |
| @override |
| Future<String> get emulatorId => null; |
| |
| @override |
| FutureOr<DeviceLogReader> getLogReader({covariant BuildableUwpApp app, bool includePastLogs = false}) { |
| return NoOpDeviceLogReader('winuwp'); |
| } |
| |
| @override |
| Future<bool> installApp(covariant BuildableUwpApp app, {String userIdentifier}) async { |
| /// The cmake build generates an install powershell script. |
| /// build\winuwp\runner_uwp\AppPackages\<app-name>\<app-name>_<app-version>_<cmake-config>\Add-AppDevPackage.ps1 |
| final String binaryName = app.name; |
| final String packageVersion = app.projectVersion; |
| if (packageVersion == null) { |
| return false; |
| } |
| final String config = toTitleCase(getNameForBuildMode(_buildMode ?? BuildMode.debug)); |
| final String generated = '${binaryName}_${packageVersion}_${config}_Test'; |
| final ProcessResult result = await _processManager.run(<String>[ |
| 'powershell.exe', |
| _fileSystem.path.join('build', 'winuwp', 'runner_uwp', 'AppPackages', binaryName, generated, 'install.ps1'), |
| ]); |
| if (result.exitCode != 0) { |
| _logger.printError(result.stdout.toString()); |
| _logger.printError(result.stderr.toString()); |
| } |
| return result.exitCode == 0; |
| } |
| |
| @override |
| Future<bool> isAppInstalled(covariant ApplicationPackage app, {String userIdentifier}) async => false; |
| |
| @override |
| Future<bool> isLatestBuildInstalled(covariant ApplicationPackage app) async => false; |
| |
| @override |
| Future<bool> get isLocalEmulator async => false; |
| |
| @override |
| DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder(); |
| |
| @override |
| Future<String> get sdkNameAndVersion async => ''; |
| |
| @override |
| Future<LaunchResult> startApp(covariant BuildableUwpApp package, { |
| String mainPath, |
| String route, |
| DebuggingOptions debuggingOptions, |
| Map<String, dynamic> platformArgs, |
| bool prebuiltApplication = false, |
| bool ipv6 = false, |
| String userIdentifier, |
| }) async { |
| _buildMode = debuggingOptions.buildInfo.mode; |
| if (!prebuiltApplication) { |
| await buildWindowsUwp( |
| package.project, |
| debuggingOptions.buildInfo, |
| target: mainPath, |
| ); |
| } |
| if (!await isAppInstalled(package) && !await installApp(package)) { |
| _logger.printError('Failed to install app package'); |
| return LaunchResult.failed(); |
| } |
| |
| final String guid = package.id; |
| if (guid == null) { |
| _logger.printError('Could not find PACKAGE_GUID in ${package.project.runnerCmakeFile.path}'); |
| return LaunchResult.failed(); |
| } |
| |
| final String appId = await _uwptool.getAppIdFromPackageId(guid); |
| |
| if (debuggingOptions.buildInfo.mode.isRelease) { |
| _processId = await _uwptool.launchApp(appId, <String>[]); |
| return _processId != null ? LaunchResult.succeeded() : LaunchResult.failed(); |
| } |
| |
| /// If the terminal is attached, prompt the user to open the firewall port. |
| if (_logger.terminal.stdinHasTerminal) { |
| await _logger.terminal.promptForCharInput(<String>['Y', 'y'], logger: _logger, |
| prompt: 'To continue start an admin cmd prompt and run the following command:\n' |
| ' checknetisolation loopbackexempt -is -n=$appId\n' |
| 'Press "Y/y" once this is complete.' |
| ); |
| } |
| |
| /// Currently we do not have a way to discover the VM Service URI. |
| final int port = debuggingOptions.deviceVmServicePort ?? await _operatingSystemUtils.findFreePort(); |
| final List<String> args = <String>[ |
| '--observatory-port=$port', |
| '--disable-service-auth-codes', |
| '--enable-dart-profiling', |
| if (debuggingOptions.startPaused) '--start-paused', |
| if (debuggingOptions.useTestFonts) '--use-test-fonts', |
| if (debuggingOptions.debuggingEnabled) ...<String>[ |
| '--enable-checked-mode', |
| '--verify-entry-points', |
| ], |
| if (debuggingOptions.enableSoftwareRendering) '--enable-software-rendering', |
| if (debuggingOptions.skiaDeterministicRendering) '--skia-deterministic-rendering', |
| if (debuggingOptions.traceSkia) '--trace-skia', |
| if (debuggingOptions.traceAllowlist != null) '--trace-allowlist="${debuggingOptions.traceAllowlist}"', |
| if (debuggingOptions.endlessTraceBuffer) '--endless-trace-buffer', |
| if (debuggingOptions.dumpSkpOnShaderCompilation) '--dump-skp-on-shader-compilation', |
| if (debuggingOptions.verboseSystemLogs) '--verbose-logging', |
| if (debuggingOptions.cacheSkSL) '--cache-sksl', |
| if (debuggingOptions.purgePersistentCache) '--purge-persistent-cache', |
| if (platformArgs['trace-startup'] as bool ?? false) '--trace-startup', |
| ]; |
| _processId = await _uwptool.launchApp(appId, args); |
| if (_processId == null) { |
| return LaunchResult.failed(); |
| } |
| return LaunchResult.succeeded(observatoryUri: Uri.parse('http://localhost:$port')); |
| } |
| |
| @override |
| Future<bool> stopApp(covariant BuildableUwpApp app, {String userIdentifier}) async { |
| if (_processId != null) { |
| return _processManager.killPid(_processId); |
| } |
| return false; |
| } |
| |
| @override |
| Future<bool> uninstallApp(covariant BuildableUwpApp app, {String userIdentifier}) async { |
| return false; |
| } |
| |
| @override |
| FutureOr<bool> supportsRuntimeMode(BuildMode buildMode) => buildMode != BuildMode.jitRelease; |
| } |
| |
| class WindowsDevices extends PollingDeviceDiscovery { |
| WindowsDevices({ |
| @required ProcessManager processManager, |
| @required Logger logger, |
| @required FileSystem fileSystem, |
| @required OperatingSystemUtils operatingSystemUtils, |
| @required WindowsWorkflow windowsWorkflow, |
| @required FeatureFlags featureFlags, |
| @required UwpTool uwptool, |
| }) : _fileSystem = fileSystem, |
| _logger = logger, |
| _processManager = processManager, |
| _operatingSystemUtils = operatingSystemUtils, |
| _windowsWorkflow = windowsWorkflow, |
| _featureFlags = featureFlags, |
| _uwptool = uwptool, |
| super('windows devices'); |
| |
| final FileSystem _fileSystem; |
| final Logger _logger; |
| final ProcessManager _processManager; |
| final OperatingSystemUtils _operatingSystemUtils; |
| final WindowsWorkflow _windowsWorkflow; |
| final FeatureFlags _featureFlags; |
| final UwpTool _uwptool; |
| |
| @override |
| bool get supportsPlatform => _windowsWorkflow.appliesToHostPlatform; |
| |
| @override |
| bool get canListAnything => _windowsWorkflow.canListDevices; |
| |
| @override |
| Future<List<Device>> pollingGetDevices({ Duration timeout }) async { |
| if (!canListAnything) { |
| return const <Device>[]; |
| } |
| return <Device>[ |
| WindowsDevice( |
| fileSystem: _fileSystem, |
| logger: _logger, |
| processManager: _processManager, |
| operatingSystemUtils: _operatingSystemUtils, |
| ), |
| if (_featureFlags.isWindowsUwpEnabled) |
| WindowsUWPDevice( |
| fileSystem: _fileSystem, |
| logger: _logger, |
| processManager: _processManager, |
| operatingSystemUtils: _operatingSystemUtils, |
| uwptool: _uwptool, |
| ) |
| ]; |
| } |
| |
| @override |
| Future<List<String>> getDiagnostics() async => const <String>[]; |
| } |