Hello Everyone
I’ve spent the last two days investigating how the Unity editor could be distributed to Linux developers using Flatpak instead of system packages in order to end dependency problems. I got some encouraging results but I can’t afford to spend more time on this. So I thought I would post my findings here in case the Unity devs, or anybody else, want to continue where I left.
What problem am I trying to solve?
Each version of the Unity editor requires different dependencies. Depending on which version of which distribution you are using these dependencies may or may not be there and if they’re not the editor can’t run at all. For example, trying to run Unity 2019 on Ubuntu 24.04 will fail because libgconf isn’t there. Trying to run Unity 2021 on Ubuntu 22.04 will fail because libssl1 isn’t there. The forum is full of people complaining about this kind of issue.
Can’t you just solve this by using a supported distribution?
No. The list of distributions officially supported by Unity evolves with each new Unity version and so does the dependencies required by the editor. If you need to run an older version of Unity on a newer distribution, or vice versa, you’re out of luck. Canonical and Red Had are not going to freeze their distribution to keep compatibility with Unity. This kind of problem will just keep happening.
What’s the solution?
Linux developers have gifted us with several ways to package and distribute applications so that they can run on any distributions without dependency issues. There systems are Flatpak, Snap, AppImage and Docker. If you package an application with one of these then it will run fine on any Linux distribution.
Each of them works in different ways. Each have its pros and cons. I have no opinion on which system is better and which is best suited to Unity. I decided to try Flatpak because it is currently the most used.
Isn’t there a Unity Flatpak on Flathub already?
It is a flatpak of the Hub, not the editor. It makes the Hub easy to install on any distribution but in doesn’t solve the dependency issues for the editor because each version of the editor require different dependencies.
How could the Unity editor be distributed with Flatpak?
We need to create a flatpak for each version of the editor. Each of these flatpaks would use different runtimes depending on the dependencies required by each version of the editor. A flatpak can also include additional dependencies non contained in the runtime if needed. For example, a flatpak of Unity 2019 would include libgconf. With this you could install any version of Unity on any distribution without any dependency problem.
What did you do?
I focused on creating a flatpak for Unity 2029.4. Since it is an old version it doesn’t run on the distributions i use (Ubuntu 24.04 and Fedora 40) making it perfect for testing.
To build the flatpak I need two files: a manifest that describes the package with its dependencies and permissions and a python script to setup and start Unity.
Here is the manifest file:
# The name of the flatpak we are going to create.
id: com.unity.Unity2019_4_40
# We use Gnome runtime as a base because it has almost everything we need.
runtime: org.gnome.Platform
runtime-version: '46'
sdk: org.gnome.Sdk
# When this flatpak is run then use our start-unity script
command: start-unity
# No need for that.
separate-locales: false
# Because it is.
tags:
- proprietary
# Poke holes into the sandboxing so Unity can access what it needs.
finish-args:
- --device=all
- --device=dri
- --filesystem=home
- --share=ipc
- --share=network
- --socket=pulseaudio
- --socket=session-bus
- --socket=x11
modules:
# We need gconf for unity. We need debug-glib and intltool for gconf.
- modules/intltool/intltool-0.51.json
- modules/dbus-glib/dbus-glib.json
- modules/gconf/gconf.json
# The module to download and install the Unity editor and our start script.
- name: unity
buildsystem: simple
build-commands:
- install -Dm755 start-unity.py ${FLATPAK_DEST}/bin/start-unity # Install our start-unity script.
- install -Dm755 apply_extra ${FLATPAK_DEST}/bin/apply_extra # Install our apply_extra script.
- printf '#!/usr/bin/env bash \nflatpak run %s run "$@" \n' ${FLATPAK_ID} > ${FLATPAK_DEST}/bin/Unity # Our fake Unity script.
sources:
# Our start-unity.py script
- type: file
path: start-unity.py
# Download the Unity editor uppon install (because we can't legally redistribute it).
- type: extra-data
filename: Editor.tar.xz
url: https://download.unity3d.com/download_unity/ffc62b691db5/LinuxEditorInstaller/Unity-2019.4.40f1.tar.xz
sha256: c592296df9dd888e5239ad7dda276bb718b33075c679a2fec9c080764644435f
size: 1914007508
# Script to install the Unity editor after it's been downloaded.
- type: script
dest-filename: apply_extra
commands:
- tar xf Editor.tar.xz
- rm Editor.tar.xz
We use the Gnome 46 runtime which contains almost all the dependencies we need. On lines 32-34 we add gconf as an additional dependency. Newer versions of Unity don’t need it.
Upon installation, the flatpak will download Unity 2019.4.40 straight from Unity’s server and install it. I can not legally redistribute Unity so this serves as a workaround and it makes the flatpak very light. We also install our start-unity script.
Here is the start-unity.py:
#!/usr/bin/env python3
import os
import stat
import subprocess
import sys
import shutil
def extract_unity_version(flatpak_id):
last_point_index = flatpak_id.rfind('.')
version = flatpak_id[last_point_index + len('Unity') + 1:]
version = version.replace('_', '.')
version += 'f1'
return version
def install(unity_version, install_dir, editor_dir):
# Check if this version of Unity is installed already
if os.path.exists(install_dir):
print(f"Unity {unity_version} is already installed.")
# Not installed, install it
else:
os.mkdir(install_dir)
os.mkdir(editor_dir)
script_path = os.path.join(editor_dir, "Unity")
shutil.copyfile("/app/bin/Unity", script_path)
os.chmod(script_path, 0o755)
def run(env, home_dir, data_dir):
# Use user's real local directory instead of the one inside the flatpak container.
# We need this so that Unity can access the license ULF file create by the Hub.
env['XDG_DATA_HOME'] = os.path.join(home_dir, ".local/share")
# Use the tmp directory inside the flatpak container.
env['TMPDIR'] = f'{env["XDG_CACHE_HOME"]}/tmp'
# Check the arguments passed to Unity.
# Path within the data dir must be replaced because we can't follow a symlink pointing inside the container.
for i in range(0, len(sys.argv)):
if sys.argv[i].startswith(data_dir):
sys.argv[i] = "/app/extra/Editor/Data" + sys.argv[i][len(data_dir):]
# Start Unity.
args = sys.argv.copy()
del args[1]
os.execvpe('/app/extra/Editor/Unity',
['/app/extra/Editor/Unity',
*args],
env)
def main():
env = os.environ.copy()
# Get flatpak ID and extract Unity's version from it
flatpak_id = env['FLATPAK_ID']
unity_version = extract_unity_version(flatpak_id)
# Get user's home directory.
home_dir = os.path.expanduser('~')
# Directory where this version of Unity should be installed
install_dir = os.path.join(home_dir, f"Unity/Hub/Editor/{unity_version}")
# Editor directory
editor_dir = os.path.join(install_dir, "Editor")
# Path of Unity's data within the Hub.
data_dir = os.path.join(editor_dir, "Data")
# Check given command
if (len(sys.argv) > 1):
command = sys.argv[1]
if command == "run":
run(env, home_dir, data_dir)
elif command == "install":
install(unity_version, install_dir, editor_dir)
sys.exit()
else:
print("Invalid command", command)
# Invalid command, display help
print("Available commands:")
print(" run Launch Unity")
print(" install Link Unity to make it visible by the Hub")
if __name__ == '__main__':
main()
This script accepts two commands: run and install.
The run command will simply start Unity. You notice we add ~/.local/share to XDG_DATA_HOME because this is where the hub put the license file and we want Unity to find it.
We also need to adjust the parameters passed to Unity by the hub. When creating a new project the hub will give Unity a template path. But because the hub doesn’t know Unity is in a flatpak the path will be wrong. But we can easily deduce the correct path.
The install command will make our flatpaked Unity visible to the hub. We simply create a directory named according to Unity’s version inside ~/Unity/Hub/Editor because this is where the hub install the editors. In there we put a simple shell script that the hub will start in place of Unity.
What works?
I managed to run Unity 2019 on distributions where it normally can’t run. I can create and open projects with the hub, make build and use Unity like I usually do. I didn’t notice any glaring issue, aside from those I’m about to discuss in the next paragraph.
What doesn’t work?
Two things: module installation through the hub and detection of external tools.
Modules can be download from Unity’s archive and installed manually. But it would be nice to be able to install them though the hub as most users do. For this to work we would need two things.
First we need the modules.json file containing the list of available modules for this version of Unity. When you install Unity though the hub this file is downloaded and installed next to Unity. But if you download Unity directly from the archive this file won’t be there. There is probably a link to download it but I couldn’t find it.
Second we would need to create a symlink from ~/Unity/Hub/Editor/editor-version/Editor/Data pointing to our Unity install inside the flatpak. That way the hub would install the modules at the right place for Unity to find them. It is easy to create this link manually but it isn’t possible to create it upon flatpak installation.
Then we have detection of external tools such as VS and Rider. Unity has a package for each and these packages contain functions to find where the tools are installed. Unfortunately these finding functions are very poorly written. The Rider package only cares about finding JetBrains’s Toolbox and will not detect Rider if it was installed manually or through flatpak. VS packages searches a desktop file with the wrong name and doesn’t parse it correctly.
In order to start these tools correctly from a flatpaked Unity, we would have to use the flatpak-spawn command (with the --host option so they are not started within the flatpak sandbox). But because VS and Rider packages don’t know how to use desktop files properly we can not make them use this command.
Should Unity devs consider distributing Unity with Flatpak?
Yes. With minors adjustments to the hub and trivial fixes to the VS and Rider packages, there is nothing preventing Unity to run happily inside a flatpak. All you need to do is to create a flatpak for each version of the editor, each of witch would have a slightly different manifest to include the dependencies it need. The Hub could download, install and start those flatpaks and the whole process would be transparent for the User.
Wanna try it?
All the files I created for this project can be downloaded here. Happy hacking.