41

I'm trying to register a custom protocol to an application on the Mac, i.e:

  1. User clicks on link with "abcdef://some/url/here"
  2. An installed application is launched with the above string passed as the first param

I've done this successfully on Windows using the information from this question:

how do I create my own URL protocol? (e.g. so://...)

I would prefer to find something that is browser-independent, in other words at the OS level. I would also like to automate this registration through a shell script, so hopefully there is a way to do this that doesn't involve the GUI.

Thanks!

Community
  • 1
  • 1
cliff.meyers
  • 17,666
  • 5
  • 51
  • 66

7 Answers7

25

I've not had occasion to use it, but some time ago I bookmarked OS X URL handler to open links to local files which is exactly what you're looking for.

The important part of the linked procedure is adding an appropriate CFBundleURLTypes to your application's Info.plist that describes the scheme. The example given there looks like this:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>Local File</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>local</string>
        </array>
    </dict>
</array>
Michael
  • 8,362
  • 6
  • 61
  • 88
Jay
  • 41,768
  • 14
  • 66
  • 83
  • 2
    I've seen this solution everywhere: when does this protocol handler actually get registered, though? Does the user have to run the app for the first time? – fatuhoku Oct 17 '13 at 09:58
  • Yes, you have to run the app to register the handler, and then it can be used transparently (assuming the app hides its dock icon). – iconoclast May 16 '14 at 14:16
  • 4
    @iconoclast since most applications in OS X are installed by copying, the `Info.plist` file is registered at time of copy (commonly to the `/Appplications/Foo` folder). In some instances if the mimetypes or URL schemes don't register automatically, a [reboot may be needed](http://apple.stackexchange.com/a/51416/147537). – tresf Jan 04 '16 at 17:14
  • What does this do specifically? Does it register `local://` to the app? – Aaron Franke Jul 06 '22 at 02:26
23

On Macs this is easy to do with AppleScript. The most detailed description is in this article, Launch Scripts from Webpage Links on Mac. I'd read that page since it includes a full walk-through and a full working example to download.

Basically, you make an event handler in a script:

on open location this_URL
    display dialog "I'm doing something with this URL: " & return & this_URL
end open location

Then save that as an Application. Then in the Finder use Show Package Contents to edit the Info.plist. You add some properties to the app to register it as a handler for your protocol.

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>Cliff's handler</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>abcdef</string>
        </array>
    </dict>
</array>
Turadg
  • 7,471
  • 2
  • 48
  • 49
  • 2
    This isn't working for me on 10.8.2. I'm able to add [MissingLink](http://www.occupantunknown.com/missinglink/missinglink.html) using after associating the scheme with the app using something like [More Internet for Mac](http://download.cnet.com/More-Internet/3000-2094_4-10559064.html). But I can't get that working with the above simple AppleScript. If I run ```open local:test``` it says ```/Users/username/local:/test does not exist```. – studgeek Jan 15 '13 at 16:58
  • 1
    Okay, this was great advice. I seem to have it working. I ran into the exact same issue with "does not exist" But after just moving the entire .app file into another directory, it seems like the OS picked it up. – counterbeing Mar 19 '13 at 02:27
  • 5
    When does the OS actually register this? – fatuhoku Oct 17 '13 at 09:59
  • 6
    Okay, I got it working too. Just as @counterbeing said, the handler works ONLY after you move the application bundle to a different (arbitrary) location. This feels bizarre, because it seems as if Mac OS X registers the application's protocol handler ON THE MOVE EVENT. I can see why this makes sense as most applications 'installed' into the `/Applications` directory just by having the user drag it in there most of the time. This way any installed applications (whether dragged into Applications directory or moved in by a `.mpkg` installer) will have their handlers registered. – fatuhoku Oct 17 '13 at 10:18
  • How does this actually work? If I write `abcdef://test`, how does macOS call the app? Is it a command line argument? Some other kind of communication? How do I read the values from inside my app once it's registered? – Aaron Franke Jul 06 '22 at 03:13
13

This question is a decade old(!) but a Google search brought me here so I wanted to mention something I just discovered.

Platypus is an open source tool that allows you to create standalone "Applications" from a shell script or other scripting language. Although it's really just a script wrapper, it does enable some cool things like dialog boxes and menu bar items.

Critically, it even enables you to register your "app" as a handler for your own custom URL scheme. From the docs:

Register as URI scheme handler makes the app register as a handler for URI schemes. These can be either standard URI schemes such as http or a custom URI schemes of your choice (e.g. myscheme://). If your app is the default handler for a URI scheme, it will launch open every time a URL matching the scheme is opened. The URL is then passed to the script as an argument.

Setup is dead simple. Just provide your script, enter your desired scheme name on the advanced settings page and then click to build the app (it's all automated). Everything after the scheme and forward slashes will be passed as the argument to your script.

For example, you could use the following bash script as a handler for the "speak://" protocol.

#!/usr/bin/env bash
# The 'say' command on macOS will speak the provided text through the speaker
say $1

You could invoke it by entering speak://say-something-funny into your browser or by using the open command on the command line:

$ open "speak://hello-from-the-command-line"
Mark Thomson
  • 739
  • 5
  • 12
  • I can manage to have `open -a App scheme://test` to work but not the simple form `open scheme://test`, any idea on how to define (if possible using commands only) the default handler for a given uri-scheme? – cglacet May 06 '20 at 10:23
  • 1
    Ah, I found why it didn't work, I still had LinCastor as the default even though the application was not running. Removing made this work as expected. – cglacet May 06 '20 at 11:04
  • Thank you, I have been trying for 5 hours to get this to work, The Platypus works (as of Dec 2020) – Jordan Réjaud Dec 26 '20 at 07:04
7

As of today, the best way I found to solve this problem on a Mac with the least overhead is using the command line duti which allows me to define in a very simple text file all my associations:

brew install duti

You will need two things. First bundle ids of the Apps you want to associate:

mdls -name kMDItemCFBundleIdentifier /Applications/MacVim.app

Second the UTI of the file type, Apple provides a list, but you can also explore the supported UTI by your app like this:

mdls -name kMDItemContentTypeTree /Applications/MacVim.app

Now make a text file somewhere in your system where you associate bundle ids with UTI:

# ~/.default-apps.duti
#
# bundle id       UTI                  role
com.apple.Safari  public.html          all
org.vim.MacVim    txmt
org.vim.MacVim    public.ruby-script

Notice that I can associate a URL handler like txmt and also file types like Ruby scripts.

In that file you I keep track of all my app preferences and reproduce them immediately after a complete fresh install or when getting an account on other Mac just running:

duti ~/.default-apps.duti
SystematicFrank
  • 16,555
  • 7
  • 56
  • 102
5

The important part of the linked page in Jay's answer is the entry in the Info.plist.

I think with Launch Services it will automatically open this app if it is the only one that can handle a particular URL scheme, else you'll need to use the trick that Charlie Martin describes.

I'm not sure what the defaults command that needs to be executed is, or if it is a launchctl command.

Matthew Schinckel
  • 35,041
  • 6
  • 86
  • 121
4

Digging up the details is difficult, but there is a preference pane called RCDefaultApp that will handle it for you. I'd still love to know how it works, will continue digging.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • Thanks very much - this is the no-thought-required solution for me on 10.9.2. Worked a treat for opening github-mac:// in Sourcetree (which used to work for me!) – ptim May 06 '14 at 13:15
0

I am not experienced much with Mac so any help would be appreciated.

Trying to add my custom protocol with the help of duti run in the post-install script of the Packages installer:

#!/bin/sh
## 
##  add_handlers.sh -- register UTI handlers for the MyApp
##
##  Requires the duti tool
##

./duti -s MyApp myapp

The handler appears in the RCDefaultApp preference pane, but when invoked from my other application, it opens Safari with that protocol in the address bar asking "Do you want to allow this page to open “MyApp”? and when clicked Allow shows error:

Safari can’t open the specified address. Safari can’t open “myapp://” because macOS doesn’t recognise internet addresses starting with “myapp:”.

Also when trying to open from the terminal:

deploy@mini-mac-mini ~ % open myapp://

LSOpenURLsWithRole() failed with error -10810 for the URL myapp://.

Maksym
  • 353
  • 1
  • 5
  • 14