7

I created custom URI scheme handler on RedHat Linux and it was working as expected. When user is redirected to the custom URI for example: myapp://abcd the browser opens application launcher popup similar to mailto: handler.

It wasn't easy to do the similar steps in Ubuntu, I tried all possible solutions available only bu none of them worked.

Here is what I have done for RedHat which worked perfectly:

  1. Add an entry in ~/.local/share/applications/mimeapps.list:

    [Added Associations]
    x-scheme-handler/myprotocol=myprotocol-handler.desktop
    
  2. Add myprotocol-handler.desktop in ~/.local/share/applications/myprotocol-handler.desktop:

    [Desktop Entry]
    Version=1.0
    Type=Application
    Exec=sh -c "$HOME/.my-handler.sh %u"
    Icon=
    StartupNotify=true
    Terminal=false
    Categories=Utility;X-XFCE;X-Xfce-Toplevel;
    MimeType=x-scheme-handler/myprotocol
    Name=My Launcher
    Comment=Launch MyProtocol
    
  3. Create ~/.my-handler.sh:

    #!/bin/bash
    printf "$code" >> file
    xdg-open https://redirect.site.com
    

I have tried the above steps on Ubuntu and it is not working, The scheme handler is only working for xdg-open command it doesn't work if I try the same URI on the browser.

I tried the below locations:

~/.config/
~/.local/share/applications/
~/.local/share/applications/packages
sudo update-desktop-database
xdg-mime command

None of the approach works as expected. Can someone point me to the right direction, my Ubuntu version is 16.04.4

dessert
  • 39,982

1 Answers1

5

I have tried the above steps on Ubuntu and it is not working

If I had to guess, I would say your desktop file might not be executable.

$ if test -x ~/.local/share/applications/myprotocol-handler.desktop; then echo 'executable'; else echo 'not executable'; fi

You can fix this like so:

$ chmod +x ~/.local/share/applications/myprotocol-handler.desktop

Give that a try first.

Also, there are a few other problems I can see right away:

  1. Are you registering the myapp scheme or the myprotocol scheme?

    You mention both of these, and it's somewhat confusing exactly what URLs you want to open.

    I will assume you want to use the myprotocol scheme, e.g. myprotocol://abcd.

  2. The "Exec" entry of your desktop file.

    Exec=sh -c "$HOME/.my-handler.sh %u"
    

    The $HOME/ is not necessary if .my-handler.sh is in your $PATH.

    The sh -c is not necessary if your script is executable, since it has the shebang line at the top. This also adds another layer of complexity, since any URLs will be expanded by the shell before they get to your URL handler script.

    The shebang line lists it as a bash script (#!/bin/bash), but you are using sh to execute it instead. I don't see any part of the script where that will make a difference, but by default sh is dash, a different shell from bash.

    $ type -a sh
    sh is /bin/sh
    $ file /bin/sh
    /bin/sh: symbolic link to dash
    
  3. The .my-handler.sh script.

    You don't need to make it a hidden file; a filename like my-handler.sh will be fine. Since I doubt that your home directory is in $PATH, there is no advantage to putting it in your home directory other than making the absolute path a little shorter. (See more about $PATH below.)

    Your shebang will work on Ubuntu:

    $ type -a bash
    bash is /bin/bash
    

    but it's a good habit to use #!/usr/bin/env bash for portability.

    You are using an uninitialized variable "$code" and appending it to a file called file. What is the purpose of this? Since file is a relative path, this will depend on the working directory, which is probably not what you want. (For URLs launched from Firefox, this will depend on what directory the browser was launched from, which might be the home directory, but could be almost anywhere else, too.)

    Your script never uses "$1" or any other arguments. This means it is essentially discarding the URL it is passed and opening https://redirect.site.com instead.

    But maybe this is just a placeholder script and this was intentional? If so, I would suggest this test script instead:

    $ cat .my-handler.sh
    #! /usr/bin/env bash
    URL="$1"
    zenity --info --text "URL: ${URL}\nPWD=${PWD}"
    

    so you can see the URL passed and directory it's being run from.

The scheme handler is only working for xdg-open command it doesn't work if I try the same URI on the browser.

If xdg-open is working, then it's just a matter of configuring the browser. Based on your comments, it looks like you are using Firefox, which handles this under Preferences:

Choose how Firefox handles the files you download from the web or the applications you use while browsing.

Applications

Choose how Firefox handles the files you download from the web or the applications you use while browsing.

This is stored in handlers.json, as you mention.

I tried the below locations

If xdg-open is already working, this should not be an issue, but one tricky thing about custom URL handlers is that there are at least four files the associations might be stored in, depending on the application / library the application uses:

  • ~/.config/mimeapps.list (the right place to make changes)
  • ~/.local/share/application/mimeapps.list (the deprecated location)
  • ~/.local/share/applications/mimeinfo.cache (the cache of the deprecated location)
  • ~/.local/share/application/defaults.list (the older deprecated location)

We'll address this issue below.

I've been doing some work on custom URL handlers lately, so I've adapted some of that for this purpose. Here are some step-by-step instructions that may help you:

  1. Check if the protocol is already registered.

    $ gio mime x-scheme-handler/myprotocol
    No default applications for “x-scheme-handler/myprotocol”
    

    In my case, the protocol is not already registered.

  2. Test the script directly.

    You may need to make it executable, like this:

    $ chmod +x ~/.my-handler.sh
    

    Then use an example URL:

    $ ~/.my-handler.sh 'myprotocol://abcd'
    

    Fix any problems here before continuing on.

  3. Add the script to your $PATH so the desktop file can find it.

    This step is optional, but it is a good habit to get into. Putting scripts into $PATH means you will not have to include the full absolute path in your desktop file, so your desktop file will not need to be changed if the path to your script changes.

    I use a bin directory like this:

    $ mkdir ~/bin/
    

    and add this to ~/.profile (note you will need to log out and log in again to see changes):

    PATH="$HOME/bin:$PATH"
    

    and finally either copy or symlink the script to ~/bin:

    $ ln -s $PWD/.my-handler.sh ~/bin/
    

    If you did this properly, you should something similar to this:

    $ type -a .my-handler.sh
    .my-handler.sh is /home/nathaniel/bin/.my-handler.sh
    

    not this:

    $ type -a .my-handler.sh
    bash: type: .my-handler.sh: not found
    
  4. Install the desktop file.

    It looks like you have done this already, but for future reference you can use the desktop-file-install command from the desktop-file-utils package:

    $ desktop-file-install --dir=$HOME/.local/share/applications/ myprotocol-handler.desktop
    

    These are the most important lines in the desktop file:

    Exec=.my-handler.sh %u
    MimeType=x-scheme-handler/myprotocol
    
  5. Make sure the desktop file is executable.

    Do this like so:

    $ chmod +x ~/.local/share/applications/myprotocol-handler.desktop
    

    This is necessary as a security measure.

  6. Register the desktop file with the x-scheme-handler/myprotocol mimetype.

    $ gio mime x-scheme-handler/myprotocol myprotocol-handler.desktop
    Set myprotocol-handler.desktop as the default for x-scheme-handler/myprotocol
    

    All this really does is change lines in ~/.config/mimeapps.list under the [Default Applications] group so it says this:

    x-scheme-handler/myprotocol=myprotocol-handler-desktop
    

    Some older applications use ~/.local/share/application/mimeapps.list, but this is officially deprecated. However, the xdg-mime command uses this location anyway:

    $ xdg-mime default myprotocol-handler.desktop x-scheme-handler/myprotocol
    

    There is also an even older deprecated file called defaults.list that is still used by some applications. Edit this file with a text editor:

    $ edit ~/.local/share/applications/defaults.list
    

    and manually add these lines:

    x-scheme-handler/myprotocol=myprotocol-handler.desktop
    

    under the [Default Applications] group.

  7. Check if it was successfully registered.

    $ gio mime x-scheme-handler/myprotocol
    Default application for “x-scheme-handler/myprotocol”: myprotocol-handler.desktop
    Registered applications:
            myprotocol-handler.desktop
    Recommended applications:
            myprotocol-handler.desktop
    

    Check xdg-mime also.

    $ xdg-mime query default x-scheme-handler/myprotocol
    myprotocol-handler.desktop
    
  8. Test some URLs from the command line.

    $ gio open 'myprotocol://abcd'
    

    Now test the same URL with xdg-open:

    $ xdg-open 'myprotocol://abcd'
    
  9. Update the mimeinfo cache.

    Some applications read ~/.local/share/applications/mimeinfo.cache instead of ~/.config/mimeapps.list. So update the cache:

    $ update-desktop-database ~/.local/share/applications/
    
  10. Test it in the browser with a local HTML file.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Example URL</title>
      </head>
      <body>
        <a href="myprotocol://abcd">myprotocol://abcd</a>
      </body>
    </html>
    

    The first time you open the link, Firefox will prompt you to find the desktop file.

    This link needs to be opened with an application.

    Navigate to ~/.local/share/applications/ and click myprotocol-handler.desktop.

    Also tick the box that says "Remember my choice for myprotocol links."

    myprotocol-handler.desktop

    It should look like this when you're done.

    Use My Launcher (default)

  11. Test it in the browser with a remote HTML file.

    There are some security differences between local and remote HTML files, so it's good to check both. You could set up some hosting for this, or just use Github or similar, but that's outside the scope of this question.

Nathaniel M. Beaver
  • 1,518
  • 12
  • 33