List ALL applications associated with file?

Hello everyone.

I’m trying to develop a script here that would list all the applications recommended for opening a file. As the Finder does when opening the Open With context menu.

On another site, I came across an interesting solution to this problem in Python. Here it is:

[format]import sys
from AppKit import NSURL
from LaunchServices import LSCopyApplicationURLsForURL, kLSRolesAll

url = NSURL.fileURLWithPath_(sys.argv[1])
for url in LSCopyApplicationURLsForURL(url, kLSRolesAll):
print url.path()[/format]

As you can see, it uses function LSCopyApplicationURLsForURL from Core Services framework. I tried to translate (to bridge) it to AsObjC, but can’t. Please help me to solve this interesting problem. If this bridging is possible, of course.

I also quote here my failed attempt for clarity:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "CoreServices"
use scripting additions

set posixPath to POSIX path of (choose file)

set theNSURL to current application's NSURL's fileURLWithPath:posixPath
set kLSRolesAll to a reference to current application's kLSRolesAll
set recommendedApplications to LSCopyApplicationURLsForURL(theNSURL, kLSRolesAll)

The use of the Launch Services in the CoreServices framework requires you to handle C data types.
And that means being able to work with ‘CF’ Core Foundation data type references and pointers.
Which you can’t do directly with AppleScript or AppleScriptObjC.

So you would have to write a command line tool with Python or Swift or any other language.
In order to access the ‘LSCopyApplicationURLsForURL’ function, as in the python code snippet.
And then call the command line tool from AppleScript with a “do shell script” command.

The other option open to you is to use the NSWorkspace class’s URLForApplicationToOpenURL: function, to retrieve the file type’s default application’s URL, something like this.


use framework "Foundation"
use scripting additions

property myApp : a reference to current application

set workspace to myApp's NSWorkspace's sharedWorkspace()

try
	set filePath to POSIX path of (choose file with prompt "Select a file type to open")
on error
	return -- User canceled selecting a file type to open
end try

set fileURL to myApp's NSURL's fileURLWithPath:filePath

set appURL to workspace's URLForApplicationToOpenURL:fileURL

if appURL ≠ missing value then
	set appName to appURL's lastPathComponent() as text
	-- Optional opening of the file in the default application
	set fileName to fileURL's lastPathComponent() as text
	set openFile to button returned of (display alert "Do you want to open the " & fileName & " file in the default application?" buttons {"NO", "YES"})
	if openFile = "YES" then
		set fileOpened to workspace's openFile:filePath withApplication:appName
		if fileOpened then
			return "SUCCESS Opening the file"
		else
			return "FAILURE Opening the file"
		end if
	else if openFile = "NO" then
		return -- User chose not to open the file in the default application
		-- You could use the Standard Additions "choose application" as alternative
	end if
else
	return -- No default application was found for the selected file type
end if

The NSWorkspace class has many useful functions for opening files and other applications, and you could always use the “choose application” command from Standard Additions, to select an alternative application to open the file type.

If I can think of another way to use ‘LSCopyApplicationURLsForURL’ function after more thought, I will let you know.

Regards Mark

Thank you very much for trying to help resolve the issue. Unfortunately, the script you provided is not what I need. I need to get not default application, but a list of all recommended applications. To understand me, select the file, then right-click and hover the mouse over the Open With menu item. The list I want appears in the pop-up window.

No, about working the AppleScript or AppleScriptObjC with ‘CF’ Core Foundation data type references and pointers. I have heard before that this is impossible. But, one day, I myself was still able to make this “impossible” possible. Here is a concrete example of how I did it for other task:


-- Convert MacRoman text to IBM866 text (russian encoding)

use AppleScript version "2.4"
use framework "Foundation"
use framework "CoreFoundation"
use scripting additions
property NSMacRomanStringEncoding : a reference to 30

set str to "熂†´™† èÆ´‚†¢™† (à.䆢†´•‡®§ß•, 1936).srt"

-- get appropriate NSStringEncoding from known kCFStringEncoding
set theEncoding to current application's CFString's CFStringConvertEncodingToNSStringEncoding(current application's kCFStringEncodingDOSRussian)
--> 2.147484699E+9

set theData to ((current application's NSString)'s stringWithString:str)'s dataUsingEncoding:NSMacRomanStringEncoding

-- convert to IBM866 encoding
return (current application's NSString's alloc()'s initWithData:theData encoding:theEncoding) as text
--> "Наталка Полтавка (И.Кавалеридзе, 1936).srt"

So I thought there might be a way to do something like this with a new task. :slight_smile:

Your example doesn’t use any CF types – it just uses an integer (via a constant) as argument, and then returns another integer. It’s only when CF types are used that it fails, and unfortunately that’s most of the time.

However, Monterey has exposed several of the Launch Services functions as NSWorkspace methods. So you can get what you want like this:

use AppleScript version "2.8" -- Monterey (12.0) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set theFile to (choose file)
set theURLs to (current application's NSWorkspace's sharedWorkspace()'s URLsForApplicationsToOpenURL:theFile) as list

You can also use URLsForApplicationsWithBundleIdentifier:, and there are methods for setting the default application.

Thanks for the clarification. I’m on Catalina and I can’t upgrade to Monterey. This means I have to use a Python solution.

There is (or not) another way that requires me to search more. If I succeed, I will post the solution here.

@KnaizidisR

Shanes solution is a cut down version of the one I posted using NSWorkspace’s URLForApplicationToOpenURL: function, which is available on all MacOS’s, and not just “Monterey”.

I also read somewhere that the Launch Services ‘LSCopyApplicationURLsForURL’ function has also been deprecated on the latest MacOS’s, I’m not sure what version of OS that it was deprecated on, but it may be worth checking if it’s still available on your “Catalina” system anyway.

If it is still there on “Catalina” I can give you a basic Swift shell script code, which you could use to get what you want, or as you’ve already stated a python script would be better, as python is installed as standard on MacOS’s, where as Swift would have to be installed to run a swift shell script.

Regards Mark

I have knocked up a quick dirty python script and swift script as a starting point for you if your interested.
And also that the forum moderators don’t mind non AppleScript code.

Let me know.

Regards Mark

It carries the deprecation notice in Monterey: “Use -[NSWorkspace URLsForApplicationsToOpenURL:] instead.” Which is what I used above. The deprecation version is listed as API_TO_BE_DEPRECATED, which I guess means we’re on notice that it will be hard deprecated in some future release.

It doesn’t look like there’s going to be much left in Launch Services.

@ Fredrik71, thanks a lot.

I created an executable utility launchHandler from your Swift code and saved it to the /usr/local/bin directory. Works great. I only had to patch kLSRolesEditor to kLSRolesAll to list all recommended applications, not just editors.

Thank you too, @Mark FX and @Shane Stanley. The problem was solved perfectly by the joint efforts of experienced users.

Example using created executable:


do shell script "/usr/local/bin/launchHandler " & quoted form of POSIX path of (choose file)

-- Result:

--  BBEdit.app
--  Google Chrome.app
--  LibreOffice.app
--  Microsoft Excel.app
--  Microsoft Word.app
--  Notes.app
--  Pages.app
--  Sublime Text.app
--  System Information.app
--  TextEdit.app

Lets give credit to the author at least.

https://gist.github.com/markd2/ff362c20463cd4ecc5fa

Regards Mark

@ Fredrik71

Hey! the solution was found for the OP, and that’s the main thing.

But a lot of smart people on various developer sites give their time and expertise for free.
They do it to help others in an unselfish way, the least we can all do in return is to give them some appreciation and credit for their efforts.

I also found that code when researching the ‘LSCopyApplicationURLsForURL’ function, and decided the code was convoluted, and did not need two for loops, but it is still a good and valid solution, if not a bit old fashioned in style.

But for me it’s simple, I would simply link to the web page, because that’s the honourable thing to do.
The OP would have their solution, and the code author can receive the gratitude.
And you would have still been helping someone yourself, and so everyone would be a winner.