How to set the kMDItemKind of a saved document on Mac OS X? - macos

I have a legacy app (minimally ported from Mac System 7 to Carbon to Cocoa) where users are reporting that the kMDItemKind metadata, as reported my mdls, of text files saved by the app seem to be set to "Microsoft Excel 97-2004 workbook". The legacy file creator and type should have been set to 'cBaS' and 'TEXT' (as was registered with Apple in ye ole ancient days), and the legacy file extension is ".bas".
What sets the kMDItemKind metadata of saved files under Mac OS X?
How do I make sure that the kMDItemKind is set correctly when saving these text files, so that my app will open them?

You can't directly set the kMDItemKind of a file. It is derived from other metadata. The file type code 'TEXT' is quite generic. The creator code is ignored these days. The file extension is probably what the system is relying on.
Unfortunately, in your case, you have multiple apps which handle .bas files. Which of those the system picks is somewhat arbitrary and subject to change. Launch Services is assigning the kind based on which would actually be used and how that app defines the document type or UTI that's matching the file extension.
Normally, you should leave the association of files with specific applications to the user. If they want to change it, they can do so with Always Open With accessible in the Finder's File menu or context menu when the Option key is held down. Or they can use the Get Info menu.
Your best bet would be to switch to using a more-likely-to-be-unique file extension

Related

Check if an OS X app exists to open a particular file

Is there any way to check if a user has an app installed on their Mac? I need to check if the user has a necessary program anywhere to open a file with a particular extension.
You probably want to use NSWorkspace. See the section Manipulating Uniform Type Identifier Information about getting and converting file extensions into uniform type identifiers, then discover what applications support those identifiers.
But if you just want to see if a file can be opened by an application and what the application is, use -URLForApplicationToOpenURL:.
If you want a list of all applications that can open a file, you'll have to drop down the launch services API: LSCopyApplicationURLsForURL

overriding Mac app file associations via CFBundleDocumentTypes in info.plist

I develop a Mac app that saves and loads files of a unique type. The type is properly declared in the info.plist under CFBundleDocumentTypes, listed as LSHandlerRank: Owner and CFBundleTypeRole: Editor. I am releasing a new version of my app and I would like that if users who already have a previous version of my app on their machine install the new version but keep the old version also installed, the new version automatically takes over the file association for this type from the old version of the app. But the default OS behavior seems to be to grant the earliest installed app associated with a file type to be it's permanent owner unless the user manually changes it. I know that the command line tool duti can make association changes, and also the system file com.apple.LaunchServices.plist can be edited, but these don't seem like the best or most reliable way to go about this programmatically from an app. Is there any "right"/Apple-sanctioned way to do what I want?
The official, Apple-sanctioned way for an application to set the default application for a file type is probably to use their provided LSSetDefaultRoleHandlerForContentType function. This function sets the values stored in LaunchServices.
Here is the limited official documentation on how to use this API in Objective-C and Swift.
There doesn't appear to be any way to do this via Info.plist, as the first application get's set as the user preferred application. The user must change their preferred application, which you can facilitate with the above API.

How can I associate a file with my app?

I have a Cocoa app "PDFHistory" on Mac OS X that uses the NSDocument architecture to save and load PDF files that are internally formatted specially for my app. I want to make it so whenever I save a file (e.g., "mydoc.pdf") from PDFHistory, then subsequently double-clicking on mydoc.pdf will automatically open it in PDFHistory.app. However, I don't want to make it so all .pdf files are automatically opened in PDFHistory, but rather use the system default (probably Preview.app). The .pdf suffix is a requirement, though, since I need the user to be able to e-mail the files to other users who can view the file in their default PDF viewer.
The problem is that if I set the LSHandlerRank to "Owner", then all .pdf files will be opened with PDFHistory, which is bad (since I only understand the internals of the .pdf file that PDFHistory wrote out). But if I set LSHandlerRank to "Alternate", then all .pdf files will be opened to the system default app (Preview.app), which is confusing for the user who had just created the file using my app.
Once upon a time, "creator codes" could be used to implement this sort of capability, but launch services started ignoring them back in Snow Leopard (see http://tidbits.com/article/10537). UTIs are not a substitute that provide this capability (see http://boredzo.org/blog/archives/2009-09-22/how-not-to-use-utis).
Using Finder to get info on the file allows the user to specify a specific app to use to open the specific file. This supposedly works by setting a "usro" property in a the file's resource. There is some open-source code to mimic this behavior (https://github.com/AlanQuatermain/SetAppAffinity), but is uses deprecated functions, and so would cause Apple to reject the app from the App Store. Similarly, people have posted AppleScript to set this property (https://discussions.apple.com/thread/2597365), but sandboxing would prevent me from invoking it.
Although the .pdf suffix is a requirement in order to be able to send the files to users on other systems/platforms, I considered trying to have the suffix registered with two extensions as ".phistory.pdf", which would allow "file.phistory.pdf" to be opened in PDFHistory, but "file.pdf" would be opened in the default PDF viewer. However, this simply didn't work: it appears that the final suffix is the only one used by launch services, and everything before that is ignored.
So is there any way to have my app be the default app for opening files that it created itself?

Show icon for creator code on OSX

How could I display a custom icon depending on a files creator code/type code. For example I have an application that opens files with the creator code 'TSTx', how would I set the icon for that creator code?
I'm guessing that's how apps like Cyberduck show a progress icon when a file is being downloaded without changing the file extension and that's the behaviour I'm trying to replicate.
Thanks,
J
You shouldn’t rely on creator and type codes for this. Not all files have them assigned. In fact, not even all apps have unique creator codes, so that’s guaranteed to break.
If they files do exist in the file system and have proper path extensions, -[NSWorkspace iconForFile:] should do the trick. (I think that will also work with custom icons.) If the file doesn’t exist in the file system (e. g. because it’s stored in a database), -[NSWorkspace iconForFileType:] is the way to go. You can supply it with a path extension or, if you insist, with an HFS type code (which you must wrap in a string with the NSFileTypeForHFSTypeCode function).
To set a custom icon to be used by the Finder, you don’t need type and creator codes. Use -[NSWorkspace setIcon:forFile:options:].

File extension icon on Mac

My application uses new proprietary file formats with extensions never been used before. I would like to associate specific icons to display my files in finder with nice iconography. As far as I know LaunchService is responsible to handle all these data, however I'm confused where, when and how shall I create associations.
Which entries I have to add to plist?
Where I need to actually register this extension - during installation? Is there any script for this?
Add a CFBundleDocumentTypes key to your plist, see
Storing Document Types Information in the Application's Property List

Resources