Mac OSX: folder extension association programmatically - macos

Is it possible to to register a folder extension on Mac to be opened with a specific application (something like .app folders behave in a special way)? If it's possible, then how?
I'm looking for a solution similar to this: related question, only for folders, not files.
I had a look at the reference of the UTIs UTIs, but I did not find any identifier that seems suitable (e.g. something like public.folder-extension).
Is it possible to do this at all? On the GUI I did not see any way to do it either (for a folder with a specific extension, there is no "Open With..." option). [Important: I do not want to do this on the GUI, this was only a remark to say why I think it might be impossible.]

I found out a way that works for me (in case somebody else also encounters this problem):
Add the following snippet in the Info.plist file of the application bundle:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ext1</string>
<string>ext2</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>documentlogo.icns</string>
<key>CFBundleTypeName</key>
<string>My Bundle Type Name</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSTypeIsPackage</key>
<true />
</dict>
</array>
Replace ext1, ext2 with the extensions you would like to support, documentlogo.icns with the name of the icon of the document (which must be located in Application Bundle.app/Contents/Resources/documentlogo.icns), and My Bundle Type Name with a sensible name for your bundle)
In this example, any folder, to be recognized as a bundle of our application, must have the extension ext1 or ext2, and must contain a Contents/PkgInfo file, with 8 "?"s. All the other contents are up to you.
I base my solution on these sources, Document Packages, Information Property List Key Reference, Document Packages Examples.
Please, correct me if there is a better/more efficient way to do it, because I still have some doubts (e.g.: as I see, this should work also for normal files, not just Packages. Then why do we need the LaunchServices way as well? Is the application bundle the default, and the LaunchServices the way each user customizes it?)

I found how to do this manually, which I will list here for others to find, and to do this programmatically you can combine this info with the answer at: https://superuser.com/questions/273756/how-to-change-default-app-for-all-files-of-particular-file-type-through-terminal
You must have XCode installed. Open Terminal or iTerm and:
cd ~/Library/Preferences
open com.apple.LaunchServices.plist
Add or overwrite the following entry (use Cmd+F to search for "folder"):
LSHandlerContentType String public.folder
LSHandlerRoleAll String com.somecompany.someproduct
Replace the com.somecompany.someproduct with an existing name - you can see these in the same directory (~/Library/Preferences) - they end with .plist - e.g. com.macromates.textmate or com.sublimetext.2.
Alternative if you use Quicksilver: add a custom keyboard trigger for "Current Selection (Proxy Object) -> Open With -> Your App Here". I found that this also creates (and vigorously re-creates) the above association whenever you use the newly created keyboard shortcut on a folder in Finder.

Related

How do I prevent an application from being used as a default opener for ANY file?

MacOS is continually using Xcode to open various files in my OS. I already know how to set a default app opener for all files with a particular extension (.txt, .py, etc...), but I can't use this feature with "extensionless" files like .bash_profile. Is there a workaround for this other than changing the default app for each file?
My preferred solution would be if I could tell MacOS to never use Xcode as a default app opener. I'm assuming there is some config file buried away that might help me achieve this but I haven't been able to find anything to help me with this.
Looking for the same I found this answer stop-xcode-from-hijacking-my-file-associations on apple.stackexchange.
It seems that XCode is pretty persistent but using this 3rd party app https://github.com/Lord-Kamina/SwiftDefaultApps you can achieve it!
Before;
After;
Instructions;
Step 1: After installing the app, go to System preferences > SwiftDefaultApps
Step 2: Go to the Uniform Type Identifiers tab and look for public data.
Step 3: Assign, under the Editor section, the desired editor.
Step 4: Apply (the app is a little bit clumsy and sometimes it doesn't show the confirmation popup, if this is the case, just close the preference window, open it again and check that everything is ok!)
Since asking this question, I stumbled upon this MacOS system file:
~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist
I've found that you can add your own dict entries into the LSHandlers array. For instance, I added the following entry to bind all public.data file types to my Sublime application:
<dict>
<key>LSHandlerContentType</key>
<string>public.data</string>
<key>LSHandlerPreferredVersions</key>
<dict>
<key>LSHandlerRoleAll</key>
<string>-</string>
</dict>
<key>LSHandlerRoleAll</key>
<string>com.sublimetext.4</string>
</dict>
Right click on a file where you want to change the default editor
Choose Get Info (Or simply select the file and press CMD+I)
Select the editor in the Open with section
Click Change All..
Now all files of this type will be opened with the editor you selected.

How to implement a complex NSDocument-based app that imports and exports non-native file types?

I'm working on an app that supports a very complicated set of operations. It's akin to something like Xcode, in that the main document is represented by something like a project window, with numerous entries in it. The document on disk is a bundle (meaning a directory with a file & folder structure underneath).
There is at least one file type that it can import and export (.mfst), but it's not intended to directly edit this file type. That is, opening this file type results in a native document type being created, and the contents of the file being imported into it. The on-disk file is a bundle (.mproj) with numerous files contained within it.
Technically, that file is copied verbatim into the proper location inside the native document bundle. Any changes to the data contained in that file are saved into the copy in the bundle, not the copy that was imported.
That file type can be exported, too.
Question 1: Is this app a Viewer of the imported type, or an Editor? I think it's the former.
Question 2: This question on supporting imported types shows how to implement import via the NSDocument subclass, but it seems that perhaps subclassing NSDocumentController is a good way to go.
One reason for this is that if the user has already imported a .mfst file, I want to catch that fact. There are other files that might be related to an open document, and should import into that document rather than creating a new one.
Question 3: Unfortunately, some of the code to operate on the project requires that certain files exist on disk. This means that even when a new document is created in response to opening the importable file type, I need to go ahead and create the bundle on disk and copy the file there so it can be operated on. I'd like to maintain the illusion to the user that this is an untitled, unsaved document. Is that possible?
I realize this goes against Apple's "modern" notion of documents that don't need to be saved. Maybe it would be better to just have all operations auto-save. I know I've never been comfortable not being able to explicitly save a document. I'm not actually sure what the recommended UI is these days (Apple seems to have reversed course on this).
Recommendations welcome.
The behaviour sounds like a Viewer of the original file because it can not alter the file.
For exported file types, add these to your application's Info.plist file using the UTExportedTypeDeclarations key value. An example from Font Pestle is below. Font Pestle does not open or edit CSS, but it does export the format:
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.source-code</string>
<string>public.utf8-plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>Cascading Style Sheet</string>
<key>UTTypeIdentifier</key>
<string>eu.miln.font-pestle.css</string>
<key>UTTypeReferenceURL</key>
<string>http://www.w3.org/Style/CSS/</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>css</string>
</array>
</dict>
</dict>
Subclassing NSDocumentController is a reasonable place to check for previously imported copies of the file being opened.
If you find yourself writing hundreds of lines of code in your NSDocumentController subclass, reconsider your design. The subclassing required should be minimal.
Use NSDocument's support for NSFileWrapper.
NSFileWrapper is designed to help ease the managing bundle based documents. NSDocument and NSFileWrapper will handle saving temporary copies of your untitled documented before the user actively saves or needs to pick a destination for the document.
I highly recommend reading Apple's About the Cocoa Document Architecture and following its guidelines as closely as possible. This will save you time and, hopefully, make maintaining your application easier as Apple evolve their underlying frameworks.

How to create snippet subfolders in textmate bundle

I've just discovered textmate and I love it. I would love to use it as a way of storing my own snippets. I know how to do this in textmate but as I want to add loads of snippets I don't want them to become disorganised. I would like to add them into organised subfolders under the relevant bundle. eg under the shell script bundle I would like to add a folder that keeps all my networking snippets together. I cant find anywhere how to do this but I know it can be done as some bundles are organised like this.....Help
I managed to figure this out with a lot of trial and error and starting with this Superuser answer.
The only way to do it in TextMate 2.0 is to manually edit the info.plist file for your bundle. I suggest doing this on an exported copy of the bundle and reloading it into textmate. To export a bundle right click on the bundle in bundle editor and click Export Bundle....
Start by adding a mainMenu section at the top level of the plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
<key>mainMenu</key>
<dict>
</dict>
</dict>
</plist>
From what I can tell, the mainMenu dict supports 3 keys: excludedItems, items, and submenus. The excludedItems and items are arrays containing a list of UUIDs of either bundle items (snippets, commands, etc.) or submenus. You can get the UUID of a command or snippet by opening it in textmate and finding the uuid key; it'll look like:
<key>uuid</key>
<string>0A2DB1AC-3049-4BD5-8931-641E716990F9</string>
Once you have the UUIDs of your items you can list them in items to populate the bundle menu in the order you wish, e.g.:
<key>items</key>
<array>
<string>409b0e74-9ab5-4d35-b957-9ddf23a71c0c</string>
<string>------------------------------------</string>
<string>d2c991dc-a00e-4247-8479-f2d29f387319</string>
</array>
If you use a series of - characters in lieu of a UUID, it will create a separator in the menu. Likewise, if there are snippets you don't want to display in the bundle's menu you can add them to excludedItems.
To create submenus you have to define them inside submenus, like so:
<key>submenus</key>
<dict>
<key>71BE58B2-E486-4B21-93F1-C208D4914099</key>
<dict>
<key>items</key>
<array>
<string>6D0B2B9D-62C7-4842-BA28-F3379E887D93</string>
<string>CADC55BD-0D0A-48C8-B296-35FA7AAE09CA</string>
</array>
<key>name</key>
<string>C++ Snippets</string>
</dict>
</dict>
Each submenu needs to have an associated UUID inside <key>...</key>. I created one from an online UUID generator. You can then add the submenu's UUID to the top-level items array to add the submenu to your bundle's menu.
Finally, when loading your bundle into textmate you must first delete all cached instances of the bundle from:
~/Library/Application Support/Avian/Bundles
~/Library/Application Support/Avian/Pristine Copy/Bundles
If you don't, textmate will sometimes ignore the newly loaded bundle. Not sure if there's a cleaner way to reload a bundle, but deleting it worked for me.
For a complete example see this commit in the ROS bundle on my Github.
Just some extra info on the excellent answer above
As of TM2 rc23, you can access the UUID of an existing item by right-clicking on it in the bundle editor window (accessed with cntrl-option-command-B)
You can create a UUID in terminal.app with the command uuidgen (you could also make this into a command if you use this often)
TM2 doesn't need the cache clearing - it watches for changes in the plist.
#user96157 is clear about this, but note you have to also add your new submenu to the mainMenu. So:
<key>mainMenu</key>
<dict>
<key>items</key>
<array>
<string>COPY-UUID-FOR-YOUR-NEW-SUB-MENU-HERE!</string>

How to remove the dock icon of a shell executable?

I have a java application built with Eclipse, for Mac OS X.
This app is installed via a .pkg file and supposed to be daemonized. Everything works fine, with Macbooks (Pro, Retina), but with the iMac I work on, when the application launches, i have an icon on the Dock, as you can see on the
following link.
I have already tried the solution in this topic: stackoverflow.com/a/620950/3641679 but it didn't work (I still have the Dock icon). Currently the Info.plist looks like this.
What can I do?
Thank you for the time you'll be taking to help me.
Informations (assuming the app name is testapp)
I stop or start the daemon using launchctl start/stop
When I double click on the executable (in testapp.app/Contents/MacOs/testapp) i have the testapp.app in the Dock (with the icon file specified in the Info.plist). Here is a screenshot res.cloudinary.com/doit0eqlo/image/upload/v1400750376/app_k3adzh.png
Sorry for some links, I must have 10 reputation to post more than 2 links.
So, I finally found the solution! The solution is in several steps.
Step 1: Editing the Info.plist
I had to add the LSBackgroundOnly key. It is a string and has to be set to 1.
As said in the Apple Documentation :
LSBackgroundOnly
specifies whether this app runs only in the background. If this key exists and is set to “1”, Launch Services runs the app in the background only.
Information:
Although the documentation specifies this key is a boolean, setting it to a string with the value 1 in it does the trick.
To do so:
Go to your app's folder
Go into the .app's folder then the Contents one (eg. /Applications/test.app/Contents)
Open the Info.plist with any text editor you want (SublimeText, TextEdit,Xcode, etc.)
Add the following lines before the closing dict tag (</dict>)
<key>LSBackgroundOnly</key>
<string>1</string>
Save everything.
Step 2: Edit the appname.ini
Initially I only did the part 1, so it wasn't enough. I found the solution in this question.
The file is in the 'Contents/MacOs' folder inside your application's .app (e.g /Applications/testapp.app/Contents/MacOs/testapp.ini).
Open the .ini file (with any text editor you want).
Before the -vmargs line, add the following line: -nosplash
After the -vmargs line, add the following two lines:
-Xdock:hidden
-Dapple.awt.UIElement=false
Save the file, and now you can launch the app: it shouldn't be any icon neither in the Dock nor in the 'Force Quit' window, but your app should be running in the background.
Hope this helps,
Add this to your info.plist: -
<key>LSUIElement</key>
<true/>
Note that the value here is set to 'true' and not 1
As the Apple docs state: -
Specifies whether the app is an agent app, that is, an app that should not appear in the Dock or Force Quit window. See “LSUIElement” for details.

Access sidecar files in a Mac sandboxed app

I need to access sidecar XMP files in a document-based photo editor application.
The image files are the documents, and I need to access the sidecar XMP file when the user open and save an image document.
Is it possible to access sidecar files (such as XMP) in a sandboxed document-based application?
I understand that it's not possible by default, but what is the minimal temporary security exception that is needed to allow that?
Is there a workaround for this without using temporary exception?
Note that it's impossible to guarantee the the image files document-scoped bookmarks to the side-cars (as they might created by other apps on different platforms), so this solution won't work.
While this question is old I thought I would share my solution. You can add an entry to your CFBundleDocumentTypes section in your apps info.plist with the NSIsRelatedItemType set to true. Then your sandboxed app will be able to open any file the user gives permission to with the same name but has the extensions that you list. Here is an example for an xmp sidecar file:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>xmp</string>
</array>
<key>CFBundleTypeName</key>
<string>XMP sidecar</string>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>NSIsRelatedItemType</key>
<true/>
</dict>
</array>

Resources