I have an AppleScript applet for which have set up a custom URL scheme like this:
I’ve edited the info.plist file in the applet accordingly:
I’ve created a bookmark in Safari which has this:
When I click on the bookmark, the “MyScript” applet launches and runs code which I have inside the “on open location” handler. That handler gets the URL currently frontmost in the web browser. The last command inside the handler is “run” which causes more code in the applet to run – displaying a dialog which sets a text box to the URL retrieved by the open location handler.
My problem is that if the MyScript applet is already running, when clicking on the bookmark:
– the applet becomes front most and runs its code but, code inside the "on open location" handler does not run; and
– when the applet is quitted, another instance starts and the code inside the "on open location" handler does run.
The first behaviour makes sense as an open applet can’t receive the “on open location” event – it is already showing a dialog. But, is there a way to prevent the custom URL scheme from always launching a new instance of the applet ?
You could try adding a boolean LSMultipleInstancesProhibited entry to the Info.plist file.
Good idea but didn’t work. LSMultipleInstancesProhibited doesn’t prevent sequential launching of the same applet. So, when the 1st instance quits, the 2nd starts.
It seems to come down to how the custom URL scheme works. I’ve not found any official Apple documentation to indicate why it opens a 2nd instance of the applet after it succeeds in making the running instance frontmost and visible.
As a workaround, I’ve got a companion applet which is opened by a custom URL scheme, does some processing, launches the main applet (passing a URL) and quits. Currently I have an Automator workflow service to handle that task but, the companion applet approach seems much quicker – it’s not held back waiting while the Automator Runner starts up. Not as elegant as I’d hoped but it works and is an improvement.
You could share your code, which could very well shed some light on the issue.
I’ve placed this handler immediately after the global definitions in my applet:
-- Testing a custom URL scheme
on open location this_url
tell me to activate
display dialog "Well, applet was started: " & this_url
using terms from application "Safari"
tell application "Safari"
set get_URL to URL of current tab of first window
end using terms from
end open location
The get_URL variable is used elsewhere in the applet.
But, that code does not run if the applet is running when I click on the bookmark – it is displaying a modal window. I suspect there’s not much I can do to get the app to interrupt the modal window and respond.
Sorry for the delay.
To start with, I’d definitely want to look at the two lines:
tell me to active
I would check whether you need/want that first line in. I highly suspect you don’t. I know why you’ve done it - to bring the dialog to the foreground. But that’s only in there for testing purposes, so just send a notification instead, and get rid of that line.
run could conceivably be causing some mischief. Generally speaking, you want to define your on run handler and have it contain code that is purely for initialising things at the start up of the app(let). The code should only ever execute once, and as determined by the applet, rather than by your call. Instead, create your own handler with its own name, and call that.
You don’t need using terms from. Delete it.
It sounds like there’s still a lot of your code you’re not sharing, which sounds like it could need a double-checking too. I’m curious what is in your run handler. And these global definitions (you should avoid globals, there’s never any need for them).
But I think you could think about restructuring the way you have things tied together. The app that contains the open location handler that is the core bit of a custom URL scheme really shouldn’t have to do anything more than this one thing. It ought not to be left running in the background. It should receive the URL, and simply decide who it’s intended for, and send it on to another app, which can bare the burden of doing the heavy lifting.