Working with Uno

📖 Overview

The Uno Platform is an open-source project that is released under the permissive Apache 2.0 license. The source code is provided to you, and you can do whatever you like with it, provided you comply with the license terms - e.g., preservation of copyright and license notices, the release of liability and warranty.

If you choose to use the Uno Platform (and we sincerely hope you do) it's important that you know how to work with the internals of the Uno Platform as, without a commercial support agreement in place, the Uno Platform is provided to you under a "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND basis. This is true for all open-source projects. Unfortunately, too many organizations forget this and inadvertently damage open-source software projects.

If your organization requires a deeper level of support beyond our community support, please contact us. Our professional support is more than a contract – it is a shared responsibility for your project success. Our engineering team will collaborate with you to ensure the success of your projects, and our custom application development team at nventive is also available to lend its expertise.

This module will introduce to the internals of the Uno Platform code-base. The team has built-in plenty of escape hatches that enables you to be autonomous without being dependant on pull-requests being merged. We hope that this knowledge will enable you to become self-reliant, to not push your pull-requests if you are ever caught in a jam and ultimately become a regular contributor to the open-source project. A growing open-source project is a healthy open-source project. 💖

💡 Walk through the codebase

What's implemented

  1. 🎯 Visit uno/src/Uno.UI/Generated to learn what features are implemented and consumed by the program that generates the Uno Platform's documentation.
  2. 📚 What is Uno.NotImplemented? Note that you can make not implemented APIs fatal exceptions by setting ApiInformation.IsFailWhenNotImplemented = true.
  3. 📚 What is the UWP Sync Generator?
  4. 📚 What is the purpose of the Generated folder?

UI implementations

  1. 🎯 Visit the source code of where XAML controls can be found - uno/src/Uno.UI/UI/Xaml.
  2. 🎯 Note usage of partial classes and the naming the convention of MyControl.cs, MyControl.iOS.cs, MyControl.Droid.cs, MyControl.wasm.cs.

Source code generation

  1. 🎯 Visit the source code at uno/src/SourceGenerators
  2. 🎯 Read https://github.com/unoplatform/uno/pull/1241/files

Integration Tests

  1. 🎯 Visit the samples app which is deployed from master after every commit.
  2. 🎯 Visit source code at uno/src/SamplesApp
  3. 📚 If you contribute a pull-request, then we expect tests to be included. This is our north star golden example of automated integration test w/droid, ios, wasm heads, and screenshot targeting

Visual Studio Solution Filters

Visual Studio 2019 introduced a new feature called solution filtering which allows developers to load a subset of projects in a solution. The Uno Platform has solution filters for each one of the target framework monikers (also referred by the team as heads):

  • Uno.UI-Android-only.slnf
  • Uno.UI-UnitTests-only.slnf
  • Uno.UI-Wasm-only.slnf
  • Uno.UI-Windows-only.slnf
  • Uno.UI-iOS-only.slnf

When contributing to the Uno Platform or changing Uno's internals, we highly recommend that you load just the subset that you need instead of loading the full Uno.UI.sln solution. Loading a subset of projects in a solution dramatically decreases solution load, build, and test run time, and enables you to be more productive. The team also recommends enabling the cross targeting override (see below) if appropriate.

Cross Targeting Override

One of the biggest productivity improvements, apart from using Visual Studio Solution Filters, is the usage of the cross targeting override escape hatch. It can be enabled by renaming crosstargeting_override.props.sample to crosstargeting_override.props.

There are two key knobs in the cross-targeting override:

  1. Controlling which platforms are built by Visual Studio.
  2. Overriding your local NuGet cache.

Controlling which platforms are built by Visual Studio

Unfortunately, Visual Studio for Windows does not support incremental builds on a per-target framework moniker (TFM) basis and builds all target framework monikers referenced in a project if a build is required, which means if you load the Uno Platform via the Uno.UI-Android-only.slnf solution filter with the intention of only making changes to the Android platform and make a change to a project that defines multiple target framework monikers defined, such as Uno.UI Visual Studio for Windows will compile the iOS, WebAssembly, and UWP heads.

Inside of the cross targeting override file, you'll find a property called UnoTargetFrameworkOverride which provides you with a way to selectively choose which target framework monikers are compiled by Visual Studio for Windows. It's really important that you close Visual Studio for Windows before making changes to UnoTargetFrameworkOverride. Ensure that you do or Visual Studio for Windows may become unresponsive.

<!--
    This property controls the platform built by Visual Studio.
    
    Available build targets:
                            uap10.0.17763 (Windows)
                            xamarinios10 (iOS)
                            MonoAndroid90 (Android 9.0)
                            netstandard2.0 (WebAssembly)
                            net461 (Tests)

    Only one target can be built, and the corresponding solution filter must
    be loaded in Visual Studio (see next to Uno.UI.sln).

    *** WARNING ***
    Note that changing that property while the solution is opened leads to
    unstable NuGet restore operations, and Visual Studio instabilities such
    as caching issues or crashes.

    Always unload the solution before changing or activating this property.
    *** WARNING ***
-->
<!--<UnoTargetFrameworkOverride>netstandard2.0</UnoTargetFrameworkOverride>-->

Thus, if you wanted to hack on the internals of the Uno Platform for Android:

  • Close Visual Studio for Windows.
  • Enable the cross targeting override escape hatch.
  • Change <UnoTargetFrameworkOverride> to <UnoTargetFrameworkOverride>MonoAndroid90</UnoTargetFrameworkOverride>.
  • Open the Uno.UI-Android-only.slnf solution filter in Visual Studio for Windows.

Overriding your local NuGet cache

Inside of the cross targeting override file you'll find a property called UnoNugetOverrideVersion which provides you with a way to generate a NuGet package at a specific version. If this version is found in your local NuGet cache, then it will be overridden. This escape hatch is extremely useful, and we wish that this feature existed in NuGet, Visual Studio and .NET.

Imagine you have an application that references Uno.UI at version v1.45.0 and there's something in that particular version of the Uno Platform that needs to change because it's blocking you from shipping your application to your customers.

By enabling <UnoNugetOverrideVersion>1.45.0</UnoNugetOverrideVersion> and building from source you'll never be in a situation where you are blocked waiting for pull-requests to be merged and a release to be cut. Here's how you do it:

  • Clone Uno and checkout the appropriate commit (or from master if adding new functionality) of the source code.
  • Enable the escape hatch using the version defined in your application.
  • Make the changes you need locally and build the Uno Platform.
  • UnoNugetOverrideVersion will override the version in your local NuGet cache.
  • Your application can then consume the changes without needing to update the application.
<!-- 
This property allows the override of the NuGet local cache.
Set it to the version you want to override, used in another app.
You will see the override path in the build output.
The packages are located under this directory: "%USERPROFILE%\.nuget\packages".
-->
<!--<UnoNugetOverrideVersion>1.45.0</UnoNugetOverrideVersion>-->

If after enabling UnoNugetOverrideVersion you don't see the expected results check the bin/obj folder of your consuming application and check the file modification dates. When in doubt - delete bin/obj and then start troubleshooting from a clean slate.

After you have finished with UnoNuGetOverrideVersion you'll need to clear your NuGet cache which can be done via:

nuget locals all -clear

🎯 Vendoring Uno

  1. Fork the Uno Platform source code from GitHub.
  2. Configure the NuGet package override to use the same version used in the Todo app.
  3. Make the required changes to the Uno Platform source code.
  4. Commit your changes to your fork of the Uno Platform.
  5. Build the Uno Platform in Visual Studio for Windows.
  6. Load the Todo application in Visual Studio for Windows.

🎯 Source level step debugging

  1. Clone the Uno Platform source code from GitHub.
  2. Configure the NuGet package override to use the same version used in the Todo app.
  3. Build the Uno Platform in Visual Studio for Windows.
  4. Load the Todo application in Visual Studio for Windows.
  5. Set debug points, step in and out.

🎯 Debugging the source generator

  1. Create a side app and note which version of Uno.UI is used as a PackageReference
  2. Override the NuGet package cache and use the same version for Uno.UI as is used in the side app.
  3. Build the side application which will start an initial Uno.SourceGenerationHost.exe process
  4. Attach to all the Uno.SourceGenerationHost.exe processes (there may be many) from the Uno.UI solution
  5. Rebuild the side app
  6. Your breakpoints in the source generators will hit
  7. Output from the generator is stored at obj\Debug\netstandard2.0\g\XamlCodeGenerator
  8. If you need to restart debugging after making significant code changes to the source generator, then make sure you terminate all existing processes (taskkill /fi "imagename eq Uno.SourceGeneration.Host.exe" /f /t) in between development iterations.

📚 Additional Reading Material

Commercial Support:

If your organization requires a deeper level of support beyond our community support, please contact us. Our professional support is more than a contract – it is a shared responsibility for your project success. Our engineering team will collaborate with you to ensure the success of your projects, and our custom application development team at nventive is also available to lend its expertise.

Key areas of the Uno Platform source-code:

Visual Studio Features and Extensions:

Open-Source Sustainability: