diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 6c8d9678b2..3b4d02c71c 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -741,6 +741,11 @@ String getWindowsBuildDirectory() { return globals.fs.path.join(getBuildDirectory(), 'windows'); } +/// Returns the Windows UWP build output directory. +String getWindowsBuildUwpDirectory() { + return globals.fs.path.join(getBuildDirectory(), 'winuwp'); +} + /// Returns the Fuchsia build output directory. String getFuchsiaBuildDirectory() { return globals.fs.path.join(getBuildDirectory(), 'fuchsia'); diff --git a/packages/flutter_tools/lib/src/flutter_application_package.dart b/packages/flutter_tools/lib/src/flutter_application_package.dart index 84d61959de..29a93d3f7d 100644 --- a/packages/flutter_tools/lib/src/flutter_application_package.dart +++ b/packages/flutter_tools/lib/src/flutter_application_package.dart @@ -108,7 +108,9 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { ? FuchsiaApp.fromFuchsiaProject(FlutterProject.current().fuchsia) : FuchsiaApp.fromPrebuiltApp(applicationBinary); case TargetPlatform.windows_uwp_x64: - throw UnsupportedError('Cannot build for windows_uwp_x64'); + return applicationBinary == null + ? WindowsApp.fromWindowsProject(FlutterProject.current().windowsUwp) + : WindowsApp.fromPrebuiltApp(applicationBinary); } assert(platform != null); return null; diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index ae9edaa5b2..ca849a728c 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -132,6 +132,31 @@ Future buildWindowsUwp(WindowsUwpProject windowsProject, BuildInfo buildIn 'The Windows UWP project template and build process has changed. In order to build ' 'you must delete the winuwp directory and re-create the project.', ); + } + // Ensure that necessary ephemeral files are generated and up to date. + _writeGeneratedFlutterConfig(windowsProject, buildInfo, target); + createPluginSymlinks(windowsProject.parent); + + final VisualStudio visualStudio = visualStudioOverride ?? VisualStudio( + fileSystem: globals.fs, + platform: globals.platform, + logger: globals.logger, + processManager: globals.processManager, + ); + final String cmakePath = visualStudio.cmakePath; + if (cmakePath == null) { + throwToolExit('Unable to find suitable Visual Studio toolchain. ' + 'Please run `flutter doctor` for more details.'); + } + + final Directory buildDirectory = globals.fs.directory(getWindowsBuildUwpDirectory()); + final Status status = globals.logger.startProgress( + 'Building Windows application...', + ); + try { + await _runCmakeGeneration(cmakePath, buildDirectory, windowsProject.cmakeFile.parent); + } finally { + status.cancel(); } throwToolExit('Windows UWP builds are not implemented.'); } diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart index 35a528f353..aa4a3b1c94 100644 --- a/packages/flutter_tools/lib/src/windows/windows_device.dart +++ b/packages/flutter_tools/lib/src/windows/windows_device.dart @@ -78,7 +78,7 @@ class WindowsUWPDevice extends DesktopDevice { @required FileSystem fileSystem, @required OperatingSystemUtils operatingSystemUtils, }) : super( - 'windows-uwp', + 'winuwp', platformType: PlatformType.windows, ephemeral: false, processManager: processManager, @@ -88,7 +88,7 @@ class WindowsUWPDevice extends DesktopDevice { ); @override - bool isSupported() => false; + bool isSupported() => true; @override String get name => 'Windows (UWP)'; @@ -100,7 +100,7 @@ class WindowsUWPDevice extends DesktopDevice { bool isSupportedForProject(FlutterProject flutterProject) { // TODO(flutter): update with detection once FlutterProject knows // about the UWP structure. - return false; + return true; } @override @@ -109,8 +109,8 @@ class WindowsUWPDevice extends DesktopDevice { String mainPath, BuildInfo buildInfo, }) async { - await buildWindows( - FlutterProject.current().windows, + await buildWindowsUwp( + FlutterProject.current().windowsUwp, buildInfo, target: mainPath, ); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 900f8b0543..2db6668d9b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -84,14 +84,17 @@ void main() { // Returns the command matching the build_windows call to generate CMake // files. - FakeCommand cmakeGenerationCommand({void Function() onRun}) { + FakeCommand cmakeGenerationCommand({void Function() onRun, bool winuwp = false}) { return FakeCommand( command: [ cmakePath, '-S', - fileSystem.path.dirname(buildFilePath), + fileSystem.path.dirname(winuwp ? buildUwpFilePath : buildFilePath), '-B', - r'build\windows', + if (winuwp) + r'build\winuwp' + else + r'build\windows', '-G', 'Visual Studio 16 2019', ], @@ -466,7 +469,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier FeatureFlags: () => TestFeatureFlags(isWindowsUwpEnabled: true), }); - testUsingContext('Windows build fails when the project version is out of date', () async { + testUsingContext('Windows UWP build fails when the project version is out of date', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; @@ -482,6 +485,22 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isWindowsUwpEnabled: true), }); + + testUsingContext('Windows UWP build fails after writing Cmake file', () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); + final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() + ..visualStudioOverride = fakeVisualStudio; + setUpMockUwpFilesForBuild(0); + + expect(createTestCommandRunner(command).run( + const ['winuwp', '--no-pub'] + ), throwsToolExit(message: 'Windows UWP builds are not implemented')); + }, overrides: { + Platform: () => windowsPlatform, + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list([cmakeGenerationCommand(winuwp: true)]), + FeatureFlags: () => TestFeatureFlags(isWindowsUwpEnabled: true), + }); } class FakeVisualStudio extends Fake implements VisualStudio { diff --git a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart index d7a77f56f6..f145b5e1f4 100644 --- a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart @@ -40,6 +40,24 @@ void main() { expect(windowsDevice.supportsRuntimeMode(BuildMode.jitRelease), false); }); + testWithoutContext('WindowsUwpDevice defaults', () async { + final WindowsUWPDevice windowsDevice = setUpWindowsUwpDevice(); + final PrebuiltWindowsApp windowsApp = PrebuiltWindowsApp(executable: 'foo'); + + expect(await windowsDevice.targetPlatform, TargetPlatform.windows_uwp_x64); + expect(windowsDevice.name, 'Windows (UWP)'); + expect(await windowsDevice.installApp(windowsApp), true); + expect(await windowsDevice.uninstallApp(windowsApp), true); + expect(await windowsDevice.isLatestBuildInstalled(windowsApp), true); + expect(await windowsDevice.isAppInstalled(windowsApp), true); + expect(windowsDevice.category, Category.desktop); + + expect(windowsDevice.supportsRuntimeMode(BuildMode.debug), true); + expect(windowsDevice.supportsRuntimeMode(BuildMode.profile), true); + expect(windowsDevice.supportsRuntimeMode(BuildMode.release), true); + expect(windowsDevice.supportsRuntimeMode(BuildMode.jitRelease), false); + }); + testWithoutContext('WindowsDevices does not list devices if the workflow is unsupported', () async { expect(await WindowsDevices( windowsWorkflow: WindowsWorkflow( @@ -164,6 +182,19 @@ WindowsDevice setUpWindowsDevice({ ); } +WindowsUWPDevice setUpWindowsUwpDevice({ + FileSystem fileSystem, + Logger logger, + ProcessManager processManager, +}) { + return WindowsUWPDevice( + fileSystem: fileSystem ?? MemoryFileSystem.test(), + logger: logger ?? BufferLogger.test(), + processManager: processManager ?? FakeProcessManager.any(), + operatingSystemUtils: FakeOperatingSystemUtils(), + ); +} + class FakeWindowsApp extends Fake implements WindowsApp { @override String executable(BuildMode buildMode) => '${buildMode.name}/executable';