Packaging a SDL2 application (Neverputt) as an IoT GUI
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 deploy your graphic application that supports the Wayland protocol to work with Ubuntu Frame and Ubuntu Core. This guide is for developers looking to build kiosks, digital signage solutions, infotainment systems, IoT devices or any other applications that require a graphic interface running on a screen.
We will cover:
- Setting up the tools and environment required to package and deploy your application on your desktop
- Testing if an application works with Ubuntu Frame on your desktop
- Troubleshooting some common issues
- Packaging the app as a snap and testing whether the snap works on your desktop
- Packaging the snap for an IoT device and testing it on the device
Developers use different tools and processes to build their graphic applications. For the purpose of this guide, we assume that you have an application that supports the Wayland protocol that you can test on your Linux-based desktop.
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.
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).
Checking your application works with Ubuntu Frame
There can be problems with both getting your application to work well with Ubuntu Frame and getting your application to work in a snap. To avoid confusion, we recommend first testing your application with Ubuntu Frame before packaging it as a snap. In this section, you will test your application, explore some common issues you might run into, and learn how to fix them.
Enabling Ubuntu Frame simulator
The key thing to know about connecting an app to Ubuntu Frame is that the connection is controlled by the
WAYLAND_DISPLAY environment variable. You need to set that to the same value for both processes and, because you may be using a Wayland-based desktop environment (which uses the default of
wayland-0), set it to
In a terminal window (that you’ll use for this section and the next section) type:
export WAYLAND_DISPLAY=wayland-99 ubuntu-frame&
You should see an “Ubuntu Frame” window containing a graduated grey background. You should use the “Ubuntu Frame” simulator for testing your application
Testing using Ubuntu Frame simulator
We use an example Qt application (Bomber) here. We’ve chosen this applications as it is easily packaged into a snap by downloading from the Ubuntu archive. With a bit more effort it can be replaced by your kiosk application, industrial GUI, smart fridge GUI, digital sign and more, but you will need to update your
snapcraft.yaml packing recipe to reflect how that is built.
The first step is to download the application and execute it. If you are able to see it on the “Ubuntu Frame” window, then you know that your application works with Ubuntu Frame.
Now, still in the same terminal window, type:
sudo apt install neverputt SDL_VIDEODRIVER=wayland neverputt
Now Ubuntu Frame’s window should contain the “Neverputt” game.
If your application doesn’t appear or look right at this stage, then this is the time to work out the fix, before packaging as a snap. You will see some examples of the problems you might encounter in the developer guide.
Close Neverputt (
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 how 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 * master remotes/origin/GTK3-mastermind remotes/origin/HEAD -> origin/master remotes/origin/Qt5-bomber remotes/origin/SDL2-neverputt remotes/origin/master
Once you have the customised snapcraft recipe you can snap your example applications.
Switch to the SDL example branch. Then use snapcraft to build the snap:
git checkout SDL2-neverputt 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:
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 WARNING: wayland interface not connected! Please run: /snap/iot-example-graphical-snap/current/bin/setup.sh Failure to initialize SDL (No available video device)
The first WARNING 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. As the message suggests, there’s a helper script for this. Run it and try again:
/snap/iot-example-graphical-snap/current/bin/setup.sh snap run iot-example-graphical-snap
Now Frame’s window should contain the “Neverputt” game.
Close that (Ctrl-C) and also close “Ubuntu Frame”.
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
You’ll see the Ubuntu Frame grayscale background once that instals, but (if you’ve been following the steps precisely) you won’t see Neverputt start:
$ snap logs iot-example-graphical-snap 2022-06-23T16:17:51Z iot-example-graphical-snap.iot-example-graphical-snap: WARNING: hardware-observe interface not connected! Please run: /snap/iot-example-graphical-snap/current/bin/setup.sh 2022-06-23T16:17:51Z iot-example-graphical-snap.iot-example-graphical-snap: WARNING: audio-playback interface not connected! Please run: /snap/iot-example-graphical-snap/current/bin/setup.sh 2022-06-23T16:17:51Z iot-example-graphical-snap.iot-example-graphical-snap: WARNING: joystick interface not connected! Please run: /snap/iot-example-graphical-snap/current/bin/setup.sh 2022-06-23T16:17:51Z iot-example-graphical-snap.iot-example-graphical-snap: Failure to initialize SDL (Could not initialize UDEV) 2022-06-23T16:17:51Z systemd: snap.iot-example-graphical-snap.iot-example-graphical-snap.service: Succeeded. 2022-06-23T16:17:51Z systemd: snap.iot-example-graphical-snap.iot-example-graphical-snap.service: Scheduled restart job, restart counter is at 5. 2022-06-23T16:17:51Z systemd: Stopped Service for snap application iot-example-graphical-snap.iot-example-graphical-snap. 2022-06-23T16:17:51Z systemd: snap.iot-example-graphical-snap.iot-example-graphical-snap.service: Start request repeated too quickly. 2022-06-23T16:17:51Z systemd: snap.iot-example-graphical-snap.iot-example-graphical-snap.service: Failed with result 'start-limit-hit'. 2022-06-23T16:17:51Z systemd: Failed to start Service for snap application iot-example-graphical-snap.iot-example-graphical-snap.
All these WARNING messages give the clue: you’re still developing the snap and interfaces are not yet being connected automatically. So, connect the missing interfaces and manually start the daemon:
Building your snap for other architectures
The simplest way to build your snap for other architectures is:
This uses the Launchpad build farm to build each of the architectures supported by the snap. This requires you to have a Launchpad account and to be okay uploading your snap source to a public location.
Once the build is complete, you can copy the
.snap file to your IoT device and install. Apart from the address used for
ssh this is the same as with the VM used in the last section.
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 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”.
For more information about Ubuntu Frame please visit our website.
You may also consider reading the following materials:
- How to run Flutter applications on Ubuntu Core
- How to leverage existing snaps to build a webkiosk.
- How to configure audio on Ubuntu Core
- How to enable on-screen keyboard support in Ubuntu Frame.
Need help in getting to market? Contact us
Last updated a month ago. Help improve this document in the forum.