Supporting Deep links in Linux with Gnome and Epiphany Web Apps

With the recent arrival of gnome 3.28, and with it, the Epiphany Web browser 3.28, saving a web page as a webapp has dramatically improved.  Saving a page as a webapp has several advantages:

  • Cookies are separate for each app. This helps limit tracking, but can also make managing multiple accounts much easier, like separating out your person gmail account with a work gmail account.
  • A clear separation of tasks. I spend a lot of time in Jira, confluence, and the AWS console. Keeping them as separate applications instead of digging through 50 tabs in firefox, is very useful.
  • They are treated as completely separate apps. This means that they have their own launcher with their own applications, can be pinned to the dock, and show up as separate applications in the window switcher
Each web app shows up separately in the alt-tab window switcher
Each Web App shows up as a separated application that can be pinned in the dock on the left.

Creating a web app in Epiphany is as simple as browsing to the website you want, clicking on the Menu button (三), and choose ‘Install Site as Web Application…’

Deep Links

iOS and Android support the concept of Deep Linking, also sometimes known as Universal Links. The idea, is that if you click on a link for a specific website, say Reddit, the operating system can decide to open that link with the installed Reddit App instead of the web browser.

I have found this to be a nice concept. When I get an email or slack message with a link to a Jira ticket, I want it to open up with my Jira web app, not my default web browser. After all, that was part of the point of having created these separate Web Apps. Unfortunately, there is no native support for this feature, but, since Linux is an open and configurable system, there is always a way!

Creating a new Default Web Browser

Gnome only allows registering applications based on the MIMEType. Unfortunately, all websites share the same scheme: ‘x-scheme-handler/http’. By default, gnome opens up your default browser and passes it the URL. We will create a new simple shell script and make it our default web browser. This simple shell script can do some basic parsing of URLs, then decide to open up a specific web app or to pass everything on to firefox.

A .desktop file is required to register our new App. Create a new file called:

~/.local/share/applications/http-handler.desktop

We will add the following to it:

[Desktop Entry]
Version=1.0
Name=HTTP Handler
Exec=/home/username/.local/bin/http-handler %u
StartupNotify=true
Categories=Network;GNOME;GTK;WebBrowser;
Terminal=false
Type=Application
MimeType=x-scheme-handler/unknown;x-scheme-handler/about;text/html;x-scheme-handler/http;x-scheme-handler/https;
This declares that it can handle the necessary MimeTypes for URLs. You will also notice that it executes /home/username/.local/bin/http-handler. This is the script we are going to create next, however, please change the username to be your username.

Building the Web App Script

I am just using a simple bash script to parse the URL and decide whether to open a specific web app or to open the default web browser. You can modify this or write it in any language that you want. This is just mean to be a simple example.

Create a new file named `~/.local/bin/http-handler` with the following:

#!/usr/bin/env bash
#
#

## Regular Expression Matches ##
URL=$1

# Jira
JIRA_RE=$(echo "$URL" | gawk '/^https?:\/\/company\.atlassian\.net\/.*/&&!/^https?:\/\/company\.atlassian\.net\/wiki.*/ {print "yes"}')
JIRA_EXEC="gtk-launch epiphany-jira-url"

# AWS
AWS_RE=$(echo "$URL" | gawk '/^https?:\/\/console\.aws\.amazon\.com\/.*/ {print "yes"}');
AWS_EXEC="gtk-launch epiphany-aws-helplightning-url"

if [ x$JIRA_RE = "xyes" ]; then
 exec $JIRA_EXEC "$URL"
elif [ x$AWS_RE = "xyes" ]; then
 exec $AWS_EXEC "$URL"
else
 exec gtk-launch firefox $URL
fi

Make sure you make your script executable:

chmod +x ~/.local/bin/http-handler

My script looks to see if a URL matches my Jira url, and if so, opens that webapp. Otherwise, it checks to see if it matches AWS console, and opens my AWS webapp. Otherwise, it runs firefox and opens the URL in a new window.

While there are many ways to parse the URL, this one uses gawk so we can test some regular expressions. The Jira URL was interesting because I want everything that starts with https://company.atlassian.net/* except https://company.atlassian.net/wiki/* since that is confluence, a separate app.

One thing about Epiphany Web Apps, is that there isn’t an easy way to run them directly. They must be executed through their .desktop file. This is so that they set the correct WM class so that the desktop environment knows to treat them as a separate application. Fortunately, we can use the gtk-launch program which takes a .desktop file (minus the .desktop) as a parameter, and launches it.

Fixing the .desktop files

When you install a Web App, epiphany creates a new desktop file in `~/.local/share/applications/` with a name like `epiphany-website-a8d40c5d8d04433783264b93849886b867fa11c4.desktop`.  These desktop files have the website hard coded into the Exec line. This means that we can’t pass it a URL, so it always opens up to the default page, which isn’t what we want. I haven’t yet found a way to have a default parameter that can be overridden. The trick is to create a copy of the .desktop file that does take a URL as a parameter. This means we will end up with two launchers, but we’ll set the NoDisplay parameter in our new one, so that it doesn’t show up in the launcher screen.

Copy the webapp .desktop file to a new name, something like:

cp epiphany-jira-b25783a8e196a10e6c869d284bdfff09546e43d6.desktop epiphany-jira-url.desktop

Edit your new `eiphany-jira-url.desktop` file. We are going to change the Exec line to take a URL parameter, and we are going to set the NoDisplay=true:

[Desktop Entry]
Name=JIRA
Exec=epiphany --application-mode --profile="/home/dillavou/.config/epiphany/app-epiphany-jira-b25783a8e196a10e6c869d284bdfff09546e43d6" %u
StartupNotify=true
NoDisplay=true
Terminal=false
Type=Application
Icon=/home/dillavou/.config/epiphany/app-epiphany-jira-b25783a8e196a10e6c869d284bdfff09546e43d6/app-icon.png
StartupWMClass=epiphany-jira-b25783a8e196a10e6c869d284bdfff09546e43d6
Categories=Network;GNOME;GTK;

We can now test this new launcher by using the gtk-launch app and passing in the name of our new .desktop file:

gtk-launch eipiphonay-jira-url https://company.atlassian.net/project/PR-1

Now make sure in your `http-handler` script, that you are executing your new .desktop file!

You can test your script by running:

~/.local/bin/http-handler https://company.atlassian.net/project/PR-1

to make sure it opens your web app. And, you can test the fallback to your web browser by running:

~/.local/bin/http-handler https://google.com

Set your Default Web Browser

With our script now working, the last step is to make our http-handler program the default web browser. This can be done on the command line by running:

xdg-settings set default-web-browser http-handler.desktop

If that doesn’t work, open up the gnome settings, go to Details -> Default Applications and make sure Web is set to ‘HTTP Handler’.

You can now test from the command line by running:

xdg-open https://company.atlassian.net/project/PR-1

or by clicking on a link in an email, text, instant message, etc…