Projectreunion: Proposal: Easily enable building any Windows app from a single project template

Created on 26 Feb 2021  路  8Comments  路  Source: microsoft/ProjectReunion

Proposal: Easily enable building any Windows app from a single project template

Summary

Today, there are many different "types" of Windows apps:

  1. Unpackaged
  2. Packaged Desktop
  3. Sparse Packages
  4. UWP

The development workflow for all of these different app types is vastly different, and in the case of Sparse Packages, there is no tooling support whatsoever. This proposal is to unify all of these paradigms into a single template, and allow developers to choose which app type they are building by setting a single MSBuild property in their project file:

Unpackaged app

<PropertyGroup>
  <WindowsPackageType>None</WindowsPackageType>
</PropertyGroup>

Sparse packaged app

<PropertyGroup>
  <WindowsPackageType>Sparse</WindowsPackageType>
</PropertyGroup>

Packaged desktop app

<PropertyGroup>
  <WindowsPackageType>Desktop</WindowsPackageType>
</PropertyGroup>

UWP app

<PropertyGroup>
  <WindowsPackageType>Universal</WindowsPackageType>
</PropertyGroup>

Rationale

  • The Windows app ecosystem is greatly divided in terms of developer experience. Project Reunion is all about bringing them together.
  • It allows developers to be flexible in their app choices. They can start with a UWP, and easily change to Desktop with minimal changes.
  • The tooling for this will be decoupled from VS, allowing for greater flexibility and also allow tooling and runtime to ship together.

Scope

| Capability | Priority |
| :---------- | :------- |
| Allow .NET developers to build UWP apps that use .NET6 | Must |
| Allow developers to no longer require the Windows Application Packaging project for packaged Desktop | Must |
| Allow developers to use the existing workflows for creating app packages and publishing to the store | Must |
| No changes to package.appxmanifest in order to switch between Sparse Universal or Desktop app | Must |
| Enable .NET developers to build unpackaged apps using .NET CLI | Must |
| Integrate with .NET ClickOnce deployment publishing | Must |
| Allow developers to change WindowsPackageType in VS UI | Should |
| Enable .NET developers to build Packaged apps using .NET CLI | Could |

Important Notes

There should be some default behavior that users can expect. This will be defined as:

  1. If there is no Package.appxmanifest in the project, then WindowsPackageType defaults to None
  2. If there is a Package.appxmanifest in the project, then WindowsPackageType defaults to Desktop.

Open Questions

Is WindowsPackageType the right property name? Should the existence of the Package.appxmanifest default into a Sparse app, and then developers just choose their container/package? This would mean there are only two options: Desktop and Universal.

area-Developer tools feature proposal

Most helpful comment

Some feedback/questions after reading the referenced specification.

[5.2.1.1 - Manifest Files] All new WinUI3 apps will have a package.appxmanifest file, but the SxS manifest should be removed.

What if a customer doesn't want to assert PerMonitorV2 support in their fusion manifest? Or add comctl? Or OS compat guids? Or long file path support? (Example from our app.)

[5.2.2 - WinUI3 Specific Tooling Requirements] Since WinUI has C++ customers, a special tool for generating the main method (i.e. Xaml compiler), which registers the Sparse Package and Dynamic Dependencies registration will be required.

Consider adding a switch around this behavior as some customers may want to handle registration themselves or not register in some scenarios.

[5.2.3 - Choosing your Windows APIs] The UWP target platform selector is problematic with Reunion. The Reunion APIs are designed to ship out of band with the OS, and with this, users are able to select Windows versions that are not compatible with their Reunion packages. This UI should just be disabled, since we hard code the TargetPlatformVersion (TPV) in the project file to match what reunion supports.

As a developer, I feel that dialog (and the subsequent property) are my only safeguards from accidentally bringing in code that does not support my app's target OS matrix. By disabling this dialog and fiddling with the property directly, I feel like I lose control over which OS versions I target. (Why does Reunion think it knows which TPV I want?)

[5.3.3 - Creating App Bundles and Publishing to the Microsoft Store]

msbuild WindowXamlAppCs.sln /m /p:Platform=x64 /p:UapAppxPackageBuildMode=StoreOnly /p:AppxBundle=Always /p:AppxBundlePlatforms="x64|arm64" /p:Configuration=Release

This invokes MSBuild in a recursive manner which rebuilds the project for multiple architectures. This behavior adds enormous complexity to the build and is difficult to maintain. Furthermore, a complex build is a slow build, and so this behavior will not be carried forward. Instead, we will only build individual .msix files per architecture, and we will enable developers to submit their apps to the store either by using the Windows Store Azure DevOps task, and the VS Publish->Create App Packages UI will be updated to handle individual .msix files.

The Windows Store Azure DevOps task is ... not good. Have you considered promoting StoreBroker use instead?

Would like to see more detail in this area. I don't see any consideration for p:AppxPackageSigningEnabled=false, p:GenerateAppInstallerFile, /p:UapAppxPackageBuildMode=CI, or other of those hidden nightmares.

[#491, WindowsPackageType enum examples]

<PropertyGroup>
 <WindowsPackageType>Sparse</WindowsPackageType>
</PropertyGroup>

Sounds okay on the surface. I wonder if adding a Desktop or DesktopMsix preface (or similar) would help with clarity here?

Example:

enum {
  None,
  DesktopMsix,
  DesktopMsixSparse,
  Universal
}

Or if you'd like to decouple the packaging technology from the enum:

enum {
  None,
  Desktop,
  DesktopSparse,
  Universal
}

[#491, Open Questions]
Is WindowsPackageType the right property name? Should the existence of the Package.appxmanifest default into a Sparse app, and then developers just choose their container/package? This would mean there are only two options: Desktop and Universal.

Property name sounds good. With regards to .appxmanifest sensing, I would prefer if no magic behavior occurs and if I chose the wrong WindowsPackageType, I'd fail. Defaulting to the most confusing / least used packaging format will also be super confusing. (Theoretical customer: Why is my MSIX empty?!)

All 8 comments

Some feedback/questions after reading the referenced specification.

[5.2.1.1 - Manifest Files] All new WinUI3 apps will have a package.appxmanifest file, but the SxS manifest should be removed.

What if a customer doesn't want to assert PerMonitorV2 support in their fusion manifest? Or add comctl? Or OS compat guids? Or long file path support? (Example from our app.)

[5.2.2 - WinUI3 Specific Tooling Requirements] Since WinUI has C++ customers, a special tool for generating the main method (i.e. Xaml compiler), which registers the Sparse Package and Dynamic Dependencies registration will be required.

Consider adding a switch around this behavior as some customers may want to handle registration themselves or not register in some scenarios.

[5.2.3 - Choosing your Windows APIs] The UWP target platform selector is problematic with Reunion. The Reunion APIs are designed to ship out of band with the OS, and with this, users are able to select Windows versions that are not compatible with their Reunion packages. This UI should just be disabled, since we hard code the TargetPlatformVersion (TPV) in the project file to match what reunion supports.

As a developer, I feel that dialog (and the subsequent property) are my only safeguards from accidentally bringing in code that does not support my app's target OS matrix. By disabling this dialog and fiddling with the property directly, I feel like I lose control over which OS versions I target. (Why does Reunion think it knows which TPV I want?)

[5.3.3 - Creating App Bundles and Publishing to the Microsoft Store]

msbuild WindowXamlAppCs.sln /m /p:Platform=x64 /p:UapAppxPackageBuildMode=StoreOnly /p:AppxBundle=Always /p:AppxBundlePlatforms="x64|arm64" /p:Configuration=Release

This invokes MSBuild in a recursive manner which rebuilds the project for multiple architectures. This behavior adds enormous complexity to the build and is difficult to maintain. Furthermore, a complex build is a slow build, and so this behavior will not be carried forward. Instead, we will only build individual .msix files per architecture, and we will enable developers to submit their apps to the store either by using the Windows Store Azure DevOps task, and the VS Publish->Create App Packages UI will be updated to handle individual .msix files.

The Windows Store Azure DevOps task is ... not good. Have you considered promoting StoreBroker use instead?

Would like to see more detail in this area. I don't see any consideration for p:AppxPackageSigningEnabled=false, p:GenerateAppInstallerFile, /p:UapAppxPackageBuildMode=CI, or other of those hidden nightmares.

[#491, WindowsPackageType enum examples]

<PropertyGroup>
 <WindowsPackageType>Sparse</WindowsPackageType>
</PropertyGroup>

Sounds okay on the surface. I wonder if adding a Desktop or DesktopMsix preface (or similar) would help with clarity here?

Example:

enum {
  None,
  DesktopMsix,
  DesktopMsixSparse,
  Universal
}

Or if you'd like to decouple the packaging technology from the enum:

enum {
  None,
  Desktop,
  DesktopSparse,
  Universal
}

[#491, Open Questions]
Is WindowsPackageType the right property name? Should the existence of the Package.appxmanifest default into a Sparse app, and then developers just choose their container/package? This would mean there are only two options: Desktop and Universal.

Property name sounds good. With regards to .appxmanifest sensing, I would prefer if no magic behavior occurs and if I chose the wrong WindowsPackageType, I'd fail. Defaulting to the most confusing / least used packaging format will also be super confusing. (Theoretical customer: Why is my MSIX empty?!)

Some other miscellanea before I forget:

  • Packaging toolset must support the packaging of "executable" projects and all dependencies. That is, it should support the ability to gather up the artifacts for both a hypothetical Exe.csproj and AddonDll.csproj, overlaying the outputs. The Windows Application Packaging project does not support this today and it's a pain point.
  • Didn't see any talk about Package.StoreAssociation.xml

Thank you @riverar for the feedback!

[5.2.1.1 - Manifest Files] All new WinUI3 apps will have a package.appxmanifest file, but the SxS manifest should be removed.

What if a customer doesn't want to assert PerMonitorV2 support in their fusion manifest? Or add comctl? Or OS compat guids? Or long file path support? (Example from our app.)

@riverar they can opt-out. This is only about the default for new projects, projects with a lot of existing legacy will just move their apps forward.

Consider adding a switch around this behavior as some customers may want to handle registration themselves or not register in some scenarios.

This switch already exists, you can disable the compiler generated main by adding this:

<DefineConstants>DISABLE_XAML_GENERATED_MAIN</DefineConstants>

As a developer, I feel that dialog (and the subsequent property) are my only safeguards from accidentally bringing in code that does not support my app's target OS matrix. By disabling this dialog and fiddling with the property directly, I feel like I lose control over which OS versions I target. (Why does Reunion think it knows which TPV I want?)

The problem with the current TPV selector is it creates discrepancies between what we support and what you can choose. Choosing your Reunion libraries in Nuget is essentially equivalent to selecting your TPV.

The Windows Store Azure DevOps task is ... not good. Have you considered promoting StoreBroker use instead?

This is great feedback, thank you! What do you like about StoreBroker over the dev ops task? I haven't found good documentation on this subject, so I'm eager to hear your thoughts.

Would like to see more detail in this area. I don't see any consideration for p:AppxPackageSigningEnabled=false, p:GenerateAppInstallerFile, /p:UapAppxPackageBuildMode=CI, or other of those hidden nightmares.

Also great feedback. What is your preference for AppxPackageSigningEnabled and GenerateAppInstallerFile? The UapAppxPackageBuildMode properties shouldn't do anything. We should use the SelfContained property to determine whether or not the MSIX will contain all of the .NET/Reunion assemblies in them or not.

Packaging toolset must support the packaging of "executable" projects and all dependencies. That is, it should support the ability to gather up the artifacts for both a hypothetical Exe.csproj and AddonDll.csproj, overlaying the outputs. The Windows Application Packaging project does not support this today and it's a pain point.

I'm a bit confused by this one, I'm fairly aware of how the packaging project works, and this is how I would describe it works. Do you have a repro project or issue to look at?

Didn't see any talk about Package.StoreAssociation.xml

I wasn't expecting any difference here, but perhaps it's worth calling that out? Is there something you'd like to see?

Property name sounds good. With regards to .appxmanifest sensing, I would prefer if no magic behavior occurs and if I chose the wrong WindowsPackageType, I'd fail. Defaulting to the most confusing / least used packaging format will also be super confusing. (Theoretical customer: Why is my MSIX empty?!)

This is good feedback. I proposed this because the majority of Windows developers aren't building packaged apps. What do you think is confusing about Sparse packages?

I don't believe this proposal, nor the associated spec has been well thought out at all - sorry to be blunt but we only get one shot at this and the way things are being proposed is going to lead to more confusion. I've already commented on the spec, along with @DrusTheAxe, indicating that the choice of app model types are completely meaningless and in no way reflect what you're trying to achieve.

Reunion should be able developers enabling features, not contorting their app to fit into some set of pre-defined packaging models. For example:

  • As a developer if I want to be able to start with an unpackaged app that builds and runs without any need for packaging.
  • I might later decide that my application needs an Identity (so it can use notifications, appdata etc) - to enable this I should be able to go to the Identity tab of the Project Properties, check Identity box and then add any additional information required for Identity.
  • I might decide later that I want to take advantage of improved security model offered by the Windows App Container. Again, Project Properties, select Security tab and check the "Run in Windows App Container" box (there might be other properties on this tab relating to trust level etc).
  • To make my application awesome I also want to take advantage of the modern app lifecycle (i.e. the uwp app lifecycle). For this all I need to do is override the appropriate lifecycle methods/events. Whatever OS level registrations that need to happen should be automatically done for me.

I'm not clear on all the nuances that I've properly overlooked but I do see that the current proposal/spec in no way clears up the confusion that exists regarding desktop v uwp v packaging v sparse packaging etc

Excellent feedback @nickrandolph. For some of these points, like deciding "my app needs Identity so I can use notifications", the whole purpose of the Project Reunion effort is to make it so that you do NOT need to be MSIX packaged.

So, if we do Project Reunion correctly, there should not be any API that you have to be deciding "Hmm, I need to have identity/MSIX". Unpackaged vs packaged apps will be on the same level playing field.

Thus, being packaged MSIX vs unpackaged is purely a distribution/security choice (if we as Reunion do our jobs right). Does that help clarify things some? I know we might have not made that story clear, we're working on making this story clearer (an updated README file coming out later this week should help a bit).

@andrewleader in terms of Identity that's exactly how I see it - basically Identity is something a developer can opt in/out of via a checkbox in project properties (irrespective of how it's implemented). On an implementation level for Identity I was under the impression you'd still need to at least do a sparse package, even if this was opaque to the developer (i.e. the package is built and included as an asset alongside the application, or is dynamically generated at runtime so identity can be registered).

I also agree packaged v unpackaged is just a single checkbox. Again an opt in/out for developer to take advantage of the distribution/security model.

What I don't understand is the different "app model types" specified in this issue/spec. What do I get from switching between Desktop and Universal packaging? Is this supposed to reflect whether the app runs in the app container or not? If so, this should be a checkbox itself (i.e. first check box is to enable packaging, second checkbox (assuming first is selected) is for the app container).

My overall point is this is about enabling features based on what developers want to achieve.

The Windows Store Azure DevOps task is ... not good. Have you considered promoting StoreBroker use instead?

This is great feedback, thank you! What do you like about StoreBroker over the dev ops task? I haven't found good documentation on this subject, so I'm eager to hear your thoughts.

My experience: The Visual Studio Team Services extension for the Windows Store task breaks a lot, has poor support, and isn't used internally (e.g. Xbox). StoreBroker has great support, is stable, has excellent documentation, and is used internally. Just something to think about.

Would like to see more detail in this area. I don't see any consideration for p:AppxPackageSigningEnabled=false, p:GenerateAppInstallerFile, /p:UapAppxPackageBuildMode=CI, or other of those hidden nightmares.

Also great feedback. What is your preference for AppxPackageSigningEnabled and GenerateAppInstallerFile? The UapAppxPackageBuildMode properties shouldn't do anything. We should use the SelfContained property to determine whether or not the MSIX will contain all of the .NET/Reunion assemblies in them or not.

We hardcode AppxPackageSigningEnabled to false in our builds and separate build/signing tasks for various reasons. But I don't have a preference, just brought it up to ensure awareness. For example, there's hidden Packaging Project behavior where sideload packages are not generated in Debug configurations. "It's dangerous to go alone! Take this. 馃棥"

Packaging toolset must support the packaging of "executable" projects and all dependencies. That is, it should support the ability to gather up the artifacts for both a hypothetical Exe.csproj and AddonDll.csproj, overlaying the outputs. The Windows Application Packaging project does not support this today and it's a pain point.

I'm a bit confused by this one, I'm fairly aware of how the packaging project works, and this is how I would describe it works. Do you have a repro project or issue to look at?

Sadly it doesn't. If the project isn't executable (exe.csproj in this example), you can't add it as a dependency. Here's a hack @StefanWickDev uses to get around this. (https://stackoverflow.com/questions/48754557/packaging-winforms-application-along-with-native-dll/48772581#48772581) Big pain point for me.

>

Didn't see any talk about Package.StoreAssociation.xml

I wasn't expecting any difference here, but perhaps it's worth calling that out? Is there something you'd like to see?

Just brought it up for awareness. I suppose an app can continue to target Universal and all this works as-is.

Was this page helpful?
0 / 5 - 0 ratings