Running UWP on Linux With Uno

Yeah, really.

Published on 16 August 2020

TL;DR

At UnoConf 2020, the Uno Platform team wowed attendees with the announcement of preliminary support for Linux. This had been something I had very much been hoping for and, first chance I got, I just had to give it a try. In this article I share how I went about getting set up for building and running a UWP app on Linux using the Uno Platform.

Intro

UnoConf 2020 was held on 12th August 2020. If you weren't "there" then I would highly encourage you to check out the recording. Over the course of several hours, (virtual) attendees were treated to numerous demos and descriptions of the Uno Platform, it's use and (rather a lot on) it's history.

However, the session by CEO Francois Tanguay and CTO Jérôme Laban was were the Uno team really notched up the shock and awe. After numerous amazing announcements such as the release of Uno Platform 3.0 with out-of-the-box support for both Fluent and Material design aesthetics, and several "anything you can do [Flutter] we can do better/faster" demos, they then proceeded to blow everyone's minds by showing a UWP app running on a Raspberry Pi under Linux.

Yes, you read that correctly: Uno Platform now lets you run your UWP apps on Linux. Just let that sink in for a second.

Back? Good.

Well, I just had to give this a shot. Despite a lack of documentation it turned out to be a fairly simple process once some preliminary software had been installed and the results were honestly better than I could have hoped for (hint: keep reading to the end for a bonus section).

Below I've outlined all the steps you need to follow to get an Uno app running under Linux.

Setup

Before being able to build or run a UWP app under Linux, you'll first need to get the following set up:

Windows Terminal

We will be firing lots of commands into both Windows and Linux shells. While you don't technically need Windows Terminal, having a single app which is able to interact with both shells will really make your life easier. If you don't have it and want to install it, you can find it in the Windows Store, here.

In the following steps I endeavour to highlight which shell to use for each command by putting the OS in bold (i.e. Windows or Ubuntu).

.NET Core SDK v3.1.100

Compiling an Uno Platform project for Linux requires a fairly recent version of the .NET Core toolchain so make sure you have SDK version 3.1.100 or higher installed. The latest version can be found here.

Once you have an up to date version of the .NET Core SDK, install the latest pre-release version of the Uno ProjectTemplates. You can find latest version of the packages here which at the time of writing is version 3.1.0-dev.39.

From the Windows command line, install the templates using the following command:

dotnet new --install Uno.ProjectTemplates.Dotnet::3.1.0-dev.39

WSL2 + Ubuntu

We're going to be running our app in a Linux distribution running under WSL2. To do this you'll need to be running Windows 10 version 2004 (Build 19041) or higher and have WSL2 installed by following the instructions here.

Once you have WSL2 installed, you'll need to install a Linux distribution. This can be done from the Windows Store, I used Ubuntu 20.04 LTS which can be found here.

X Window Server

In order to run graphic apps from WSL2, we need to install an X Window Server on our Windows 10 host machine. There are a surprising number of alternatives here including Xming and VcXsrv but I went for X410 because it was in the Windows Store, super-easy to use and - until the end of August - heavily discounted to just £8.39.

After installing X410, all you need to do is run the app, the right click on it's system tray icon and click "Allow Public Networks" as shown below:

X410 Allow Public Networks

With that done, leave it running so we can...

Test

Before digging into building our own app, we're going to test our "WSL2 + X Window Server" combo. So from a command prompt inside your Ubuntu distribution run the following commands:

sudo apt-get update
sudo apt-get install vim-gtk

This will install the graphic version of Vim which we can use to check that we're able to run a graphical Linux app from Windows (just sounds weird doesn't it!).

Next find the IP address of the WSL adapter on your Windows 10 host machine. This can be done using ipconfig from the Windows command line as shown below:

Windows 10 WSL Adapter IP Address

With this in hand, enter the following on the Ubuntu command prompt (told you that you'd want Windows Terminal!) substituting your IP address appropriately:

export DISPLAY=[IP ADDRESS]:0

Finally, start vim-gtk by running the following command, again from the Ubuntu prompt:

gvim

If everything is set up correctly, you should see the following window appear:

Gvim on Windows 10

If the window doesn't appear try following the troubleshooting section here.

Build

Still with me? Aces. Now lets use Uno to create a UWP app which will run in Ubuntu!

From the Windows command prompt, navigate to the directory where you want to create the new solution and type the following:

dotnet new unoapp -o UnoLinux -w=false -wasm=false -ios=false -android=false -macos=false -sw=false

This will create a new folder named UnoLinux inside of which will be an Uno Solution containing just the UWP and Skia.Gtk head projects.

Next, still on the Windows command line, navigate to the UnoLinux.Skia.Gtk project and build it using:

cd .\UnoLinux\UnoLinux.Skia.Gtk\
dotnet build

You will probably see a few warnings but as long as you see "Build Succeeded" you should be golden. My build output looks as follows:

UnoLinux Build Output

Finally we want to build the project for the Linux runtime and publish it as a self contained executable. This is done using the following:

dotnet publish --runtime linux-x64 -c Release --self-contained

You're likely to see the same warnings again here but there shouldn't be any errors.

Once this command completes you should be able to navigate to .\bin\Release\netcoreapp3.1\linux-x64\ where you will find a UnoLinux.Skia.Gtk file.

Got it? Brills!

Running UWP on Ubuntu

Back at the Ubuntu command prompt, navigate to the bin\Release directory above. In WSL all your Windows drives should be mounted under /mnt/ so you should be able to run a command similar to the following (with [DRIVE LETTER] and [PATH] replaced):

cd /mnt/[DRIVE LETTER]/[PATH]/UnoLinux/UnoLinux.Skia.Gtk/bin/Release/netcoreapp3.1/linux-x64

Finally - and here comes the magic - run the UnoLinux.Skia.Gtk app from the Ubuntu command line using:

./UnoLinux.Skia.Gtk

Again, if everything has gone smoothly, the following window should pop-up after a few seconds:

UnoLinux Hello World

Now sit back and let this sink in for a second.

This is a Universal Windows Platform application, rendering to a Skia backend, within a GTK host, running in Ubuntu, running under Windows. Given we're this many layers down, perhaps I might be able to plant an idea:

UWP... all... the... things!

Bonus

Now, thanks to the Uno team, all the above was fairly painless and I still had some time left so.... I decided to see how far I could push UWP under Linux.

Using the UnoChat sample I created for my "Cross-Platform Real-Time Communication with Uno & SignalR" post, I updated all the Uno packages to the latest pre-release versions. I then copied the UnoLinux.Skia.Gtk project folder from the UnoLinux solution we just created and added it to the UnoChat solution. Some monkeying ensured to re-namespace everything and correct project and package references but without too much effort, I got everything building.

With baited breath, I tried this:

Woah! Without modifying any of the shared code, the exact same application compiled, ran and functioned under Linux.

That's not to say there weren't problems. There seemed to be an issue with TextBox controls which prevented me from sending messages from the Linux head and the fonts didn't quite match across the platforms. But, given this is just a preliminary release, the fact that the app could receive messages from a remote SignalR server then template and render the messages correctly on Linux is just stunning.

Absolutely. Stunning.

Code

The code for this sample is available in the "Prerelease" branch of my UnoChat repository here. Once Linux support is a little more mature, I'll update the more advanced "Uno.ChatSignalR" app I prepared for UnoConf which can be found here.

And lastly...

If you're interested in using the Uno Platform to deliver cross-platform apps or have an upcoming project for which you'd like evaluate Uno Platform's fit, then please feel free to drop me a line to discuss your project/ideas using any of the links below or from my about page. As a freelance software developer and remote contractor I'm always interested in hearing from potential new clients or ideas for new collaborations.