Managing the dependency with the Windows App SDK
By detaching features and APIs from the operating system, the Windows team has gained a lot of benefits, such as the ability to add new features and fix issues outside the regular Windows update cycle. However, as developers, we cannot take for granted that the user who installs our application will have the Windows App SDK runtime installed on their machine. As such, it's our responsibility as developers to manage this dependency in the right way. This is one of the scenarios where the difference between adopting the packaged or unpackaged model is critical, since they adopt two different ways to deploy the dependency.
The Windows App SDK runtime is made up of the following components:
- The framework package: This package contains the binaries that are used by the applications at runtime.
- The main package: This package contains multiple out-of-process components that aren't included in the framework, such as background tasks, app extensions, and app services.
- The singleton package: This package includes a long-running process that provides access to features that are shared across all applications, such as push notifications.
- Dynamic Dependency Lifetime Manager (DDLM): This package is used to control the life cycle of the Windows App SDK runtime. Thanks to this package, Windows will refrain from automatically updating the runtime if one or more unpackaged apps that use the Windows App SDK are running.
Each of these components is stored in its own MSIX package. Let's see now how to manage the deployment of the runtime based on the way you distribute your application.
Packaged apps
As previously mentioned, packaged apps have a few advantages compared to unpackaged apps. Packaged applications are described by a manifest, which includes a section called Dependencies
. This section is already used today to manage the dependency on a specific version of Windows or the Visual C++ runtime.
The dependency with the Windows App SDK runtime can be easily declared in the same section by adding the following entry:
<PackageDependency Name="Microsoft.WindowsAppRuntime.1.0" MinVersion="0.319.455.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
Thanks to this configuration, if the application is deployed to a machine that doesn't have the runtime installed, Windows will automatically download it from the Microsoft Store and install it system-wide so that future applications that you might install won't need to download it again.
In most cases, you won't have to manually include this entry. In fact, when you install the Windows App SDK NuGet package in your application, Visual Studio will add a special build task that will add this entry in the manifest for you every time you generate a new MSIX package.
However, there's still a manual requirement you have to take care of. As mentioned in the previous section, the Windows App SDK applications are dependent not just on the framework itself but, based on the features they use (for example, background tasks or push notifications), they might also need the main package and the singleton package. MSIX doesn't support having regular packages as dependencies, which means that when you deploy a packaged Windows App SDK application, the framework is automatically deployed if missing, but the other components aren't. However, these packages are included inside the framework and, as such, can be automatically deployed by using the DeploymentManager
API, which belongs to the Microsoft.Windows.ApplicationModel.WindowsAppRuntime
namespace. Thanks to this API, you can check whether one or more of the components are missing on the system and install them if necessary. This is an example implementation of the OnLaunched()
method of a Windows App SDK application, which is executed when the application starts:
protected override void OnLaunched (Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { var status = DeploymentManager.GetStatus(); if (status.Status == DeploymentStatus.PackageInstallRequired) { DeploymentManager.Initialize(); } m_window = new MainWindow(); m_window.Activate(); }
Thanks to the GetStatus()
method, we can detect the status of the various components on the system. If one or more of them is missing (which is represented by the PackageInstallRequired
value of the DeploymentStatus
enumerator), we can call the Initialize()
method to perform the deployment.
Unpackaged apps
For unpackaged apps, Microsoft provides an installer called WindowsAppRuntimeInstall.exe
, which automatically detects the CPU architecture of a system (x86, x64, or ARM64) and installs system-wide the MSIX packages that compose the runtime – framework, main, and DDLM.
The installer also supports a --quiet
parameter, which enables a silent installation with no user interaction and output messages. All the technologies and tools to create setup programs (or even just a PowerShell script) support the possibility of launching an executable as part of the installation, so it's easy to configure your installer to silently launch the WindowsAppRuntimeInstall.exe
executable before or after the deployment of the main application, and before the whole installation process is completed.
Compared to a packaged application, you won't need to use the deployment APIs here, since the WindowsAppSDKInstall
tool will take care of installing all the required packages on the system.
Upgrading the Windows App SDK runtime
The Windows App SDK runtime will continue to evolve over time, and as such, it's important for a developer to understand how future updates will be managed.
Updates can be delivered in two ways:
- If the machine has access to Microsoft Store, they will be automatically downloaded and installed.
- If the machine doesn't have access to Microsoft Store, it will be up to the application to include a newer version of the Windows App SDK runtime installer.
To control the way updates will be installed, the Windows App SDK has adopted the Semantic Versioning rules. By reading the official website (https://semver.org/), we learn that the version number is defined by three numbers, MAJOR.MINOR.PATCH, which stand for the following:
- MAJOR is incremented when you make incompatible API changes.
- MINOR is incremented when you add new functionality but with backward compatibility.
- PATCH is increased when you make bug fixes that are backward-compatible.
The runtime installed on a machine will be automatically updated only if the MINOR or the PATCH revision changes. If a new release increases the MAJOR number, instead, it will be installed side by side with the existing ones. This makes sure that newer versions of the runtime that might include breaking changes won't replace the existing ones, causing your applications to stop working properly.
Thanks to the DDLM component of the runtime, Windows will keep the old instance of the runtime installed as long as there's at least one running application that is using it. Once the application is closed, the previous version of the runtime will be uninstalled, and at the next relaunch, the app will start using the updated version.
Now that we understand how to manage the Windows App SDK dependency in our application, we're ready to start creating our first application.