How to migrate your kiosk application from Windows to Ubuntu Frame

Ubuntu Frame is the foundation for embedded displays. It provides a reliable, secure and easy way to embed your applications into a kiosk-style, IoT device, or digital signage solution. With Ubuntu Frame, the graphic application you choose or design gets a fullscreen window, a dedicated set of windows behaviours, input from touch, keyboard and mouse without needing to deal with the specific hardware, on-screen keyboard, and more.

Together with Ubuntu Core, Ubuntu Frame provides all the infrastructure you need to securely deploy and maintain graphic applications on edge devices. And while Ubuntu Core maximises performance and security of your apps, Ubuntu Frame is compatible with any Linux operating system that supports snaps.

This developer guide will show you how to migrate your Windows graphic application to work with Ubuntu Frame and Ubuntu Core. This guide is for developers looking to migrate Windows kiosks, digital signage solutions, infotainment systems, IoT devices or any other applications that are currently deployed through Windows in a kiosk environment.

We will cover:

  1. Setting up the tools and environment required to package and deploy your application on your desktop
  2. Packaging the app as a snap and testing whether the snap works on your desktop
  3. Integrating your own application
  4. Packaging the snap for an IoT device and testing it on the device

If you want to learn how to install pre-built applications such as wpe-webkit-mir-kiosk, mir-kiosk-kodi, or Scummvm, follow their official installation and configuration guides.

If you are new to Ubuntu Core, we recommend reading our getting started document. If you want to learn about building custom Ubuntu Core images, you could find information on the snapcraft docs.

Requirements

Developers use different tools and processes to build their graphic applications. For the purpose of this guide, we assume that you have a Windows application that can run through the Wine compatibility suite. If your application is written in a cross-platform framework like Qt or Flutter, it is likely better to package and run it natively on Ubuntu. See our other guides specific to those frameworks: Ubuntu Frame How-to Guides.

It is possible to work in a container or on a different computer (if snapd and X forwarding work well enough). But those options are outside the current scope.

For some of the later steps, you will need an Ubuntu One account. This will let you enable remote-build on your Launchpad account and publish on the Snap Store.

Setting up your test environment

Ubuntu Frame provides a tool for developers to simulate how their end application will look and respond in your development environment. So, you don’t need to work directly on your target device to perform the first design and usability iterations.

Open a terminal window and type:

sudo snap install ubuntu-frame

Snapcraft is a command-line utility for building snaps. This software allows users to build their own applications or software packages, and then publish them to the Snap Store.

In the same terminal window type:

sudo snap install snapcraft --classic

If you don’t have git installed, now is a good time to install it (on Ubuntu, use the command sudo apt install git).

Packaging your application as a Snap

Now that you know how to confirm that the application is working with Ubuntu Frame, the next step is to use snap packaging to prepare it for use on an IoT device. As before, this section will show you how to package your application together with some issues you might find and their troubleshoot.

Snap packaging for IoT graphics

For use with Ubuntu Core, your application needs to be packaged as a snap. This will also allow you to leverage Over The Air updates, automatic rollbacks, delta updates, update semantic channels, and more. If you don’t use Ubuntu Core, but instead another form of Linux, we recommend you use snaps to get many of these advantages.

There’s a lot of information about packaging snaps online, and the purpose here is not to teach about the snapcraft packaging tool or the Snap Store. We will, instead, focus on the things that are special to IoT graphics.

Much of what you find online about packaging GUI applications as a snap refers to packaging for desktop. Some of that doesn’t apply to IoT as Ubuntu Core and Ubuntu Server do not include everything a desktop installation does and the snaps need to run as daemons (background services) instead of being launched in a user session. In particular, you should ignore various Snapcraft extensions that help writing snap recipes that integrate with the desktop environment (e.g. using the correct theme).

Writing snap recipes without these extensions is not difficult as we’ll illustrate for each of the example programs used in the previous section.

First, you will clone a repository containing a generic Snapcraft recipe for IoT graphics.

In the same terminal window you opened at the start of the last section, type:

git clone https://github.com/MirServer/iot-example-graphical-snap.git
cd iot-example-graphical-snap

If you look in snap/snapcraft.yaml, you’ll see a generic “snapcraft recipe” for an IoT graphics snap. This is where you will insert instructions for packaging your application. This is what the .yaml file looks like:

The customised snapcraft recipe for each example described in this guide (i.e. GTK, Qt and SDL2) is on a corresponding branch in this repository:

$ git branch -a
* main
  remotes/origin/Electron-quick-start
  remotes/origin/Flutter-demo
  remotes/origin/GTK3-adventure
  remotes/origin/GTK3-mastermind
  remotes/origin/Qt5-bomber
  remotes/origin/Qt5-bomber-first-try
  remotes/origin/Qt6-example
  remotes/origin/SDL2-neverputt
  remotes/origin/main
  remotes/origin/x11-glxgears
  remotes/origin/Wine-example

Once you have the customised snapcraft recipe you can snap your example applications.

Switch to the Wine example branch. Then use snapcraft to build the snap:

git checkout Wine-example
snapcraft

Snapcraft is the packaging tool used to create snaps. We are not going to explore all its options here, but to avoid confusion, note that when you first run snapcraft, you will be asked “Support for ‘multipass’ needs to be set up. Would you like to do it now? [y/N]:”, answer “yes”.

After a few minutes, the snap will be built with a message like:

Snapped iot-example-graphical-snap_0+git.e656221_amd64.snap

You can then install and run the snap:

sudo snap install --dangerous *.snap
snap run iot-example-graphical-snap

The first time you run your snap with Ubuntu Frame installed, you are likely to see a warning:

$ snap run iot-example-graphical-snap
++ find /snap/iot-example-graphical-snap/x1/hacks -name 'setup-*'
+ for hack in $(find "${SNAP}/hacks" -name setup-\*)
+ . /snap/iot-example-graphical-snap/x1/hacks/setup-mir
++ set -x
++ export MIR_SERVER_PLATFORM_PATH=/snap/iot-example-graphical-snap/x1/usr/lib/x86_64-linux-gnu/mir/server-platform
++ MIR_SERVER_PLATFORM_PATH=/snap/iot-example-graphical-snap/x1/usr/lib/x86_64-linux-gnu/mir/server-platform
++ export MIR_SERVER_XWAYLAND_PATH=/snap/iot-example-graphical-snap/x1/usr/bin/Xwayland
++ MIR_SERVER_XWAYLAND_PATH=/snap/iot-example-graphical-snap/x1/usr/bin/Xwayland
+ for hack in $(find "${SNAP}/hacks" -name setup-\*)
+ . /snap/iot-example-graphical-snap/x1/hacks/setup-wayland-host
++ set -x
++ snapctl is-connected wayland
++ echo 'Wayland interface not connected!'
Wayland interface not connected!
++ exit 1

The WARNING “Wayland interface not connected!” is the key to the problem and comes from one of the scripts in the generic recipe. While developing your snap (that is, until your snap is uploaded to the store and any necessary “store assertions” granted), connecting many “interfaces” your snap uses needs to be done manually. Connect the wayland interface and try again:

sudo snap connect iot-example-graphical-snap:wayland
snap run iot-example-graphical-snap

After a little time Frame’s window should contain the example DNSBench app (we know it’s not a great demo application, if you know about a better one, let us know!).

Close that (Ctrl-C) and also close “Ubuntu Frame”.

Integrating your own application

Runing a Windows application on Ubuntu requires the use of a compatibility layer - Wine. The snap uses a community-maintained set of utilities that make it easier to create a snap including the Windows application along with the elements required for Wine: Sommelier Core. Refer to their documentation for more details of this layer, but some elements of the YAML are particularly interesting to use your app:

  • installer URL, if your application should be downloaded and installed, rather than bundled with the snap:
    INSTALL_URL: https://example.com/installer.exe
    
  • installer flags, if the installer has a silent mode:
    INSTALL_FLAGS: /silent
    
  • the list of Wine tricks (e.g. libriaries to be installed, see the Wine tricks wiki page):
    TRICKS: vcrun2019
    
  • the executable to run:
    # if it's installed in the Wine environment
    RUN_EXE: C:\path\to\installed\executable.exe
    # or if it's bundled with the snap
    RUN_EXE: $SNAP/executable.exe
    

Refer to Sommelier Core README to see what other variables are available.

There is a lot more to say about getting Windows apps to run under Wine, but it’s out of scope for this document.

Installing on a device

In this section, you will see how to build for and install on a device. So far, you explored the process for testing your snapped application will work on Ubuntu Frame only using your desktop. Testing on the desktop first accelerates the development process, but you still need to consider the final your edge device.

For the sake of this guide, we are using a VM set up using the approach described in Ubuntu Core: Preparing a virtual machine with graphics support.

scp -P 10022 *.snap <username>@localhost:~
ssh -p 10022 <username>@localhost
snap install ubuntu-frame
snap install --dangerous *.snap

Conclusion

From testing to deployment, this guide shows you how to use Ubuntu Frame to deploy your graphic applications. It covers topics as setting up the tools and environment on your desktop, testing if an application works with Ubuntu Frame, and packaging the application as a snap for an IoT device. It also included some issues you can encounter while working with your applications and how to troubleshoot them.

We have also shown all the steps needed to get your snap running on a device. The rest of your development process is the same as for any other snap: uploading the snap to the store and installing on devices from there. There are just a few parting things to note:

Now that the Snap interfaces are configured, the application will automatically start when the system (re)starts.

Once you’ve uploaded the snap to the store, you can request store assertions to auto-connect any required interfaces. Alternatively, if you are building a Snap Appliance, then you can connect the interfaces in the “Gadget Snap”.

Learn more

For more information about Ubuntu Frame please visit our website.

You may also consider reading the following materials:

Need help in getting to market? Contact us

Last updated 2 months ago. Help improve this document in the forum.