overriding Mac app file associations via CFBundleDocumentTypes in info.plist - macos

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.

Related

MacOS Get default application for file type

I am working on a Mac app. I ultimately want to use default app icons within my app. From the Info.plist and the Resource folder of an app I can get the .icns file and convert that to the image format I need. But I need to know the default application associated with the particular file extension, if any.
So how to get the default application that the system currently associates with a given file extension?
Don't go digging in other apps' bundles. It's always best to work at the level of abstraction that suits the question you want to ask. If you want to get the icon that the Finder (or a Mail attachment, etc) would display for a file of a particular type, use the NSWorkspace iconForFileType: method.
I think what you're looking for is part of the OSX Launch Services: LSCopyDefaultApplicationURLForContentType API. This returns the info on apps that can open specific Uniform Type Identifiers. There's also a similar API called LSCopyDefaultApplicationURLForURL to check which app opens a specific known file.

Resetting mac application in xcode

How can I reset a cocoa application in Xcode? When I run my application from Xcode all user default are saved. I would like to reset (delete) my application to create a new one with new settings and run as it would be run first time.
I found one way - I change a name of my app to a different one and it is started as new. But how can I do this with an old name?
You can use the defaults command line tool to remove all the settings, you just need the bundle id of your app (which you can find in your Info.plist file), e.g. if your bundle id is "com.foo.barApp" then you can run this from a terminal shell:
defaults delete com.foo.barApp
Is your app limited to the App Store? If so, I don't think there's a way to delete your entire application, specifically because of the sandbox restrictions. We'd need more information on how you are planning to distribute it to help.
If you just want to delete your app settings, then clear whatever database you store your app data in - [NSUserDefaults +resetStandardUserDefaults], SQLite, App Library directory, whatever. That is dependent on how/where you are storing user data, there's no one size fits all solution.

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?

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

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

Mac App Store Sandboxing - Writing a new file?

I've been playing around with an app I want to submit to the Mac App Store, and part of the functionality is simply grabbing a file the user chose by dragging or opening, and saving a modified of it to the same directory as the original file (but with a different file name).
I don't want to use a 'Save' dialog box, as that destroys the utility of the application I'm building, but it looks like that might be the only way the app would be allowed—under sandboxing requirements—to write a file to an arbitrary location (arbitrary, in this case, being in the same folder as the existing file) on the disk as a new file.
Is there any way I can approach this without disabling sandboxing? Also, if I submit the app without entitlements/sandboxing turned on today, will it be approved by Apple (supposing it passes all the other requirements), or are they already turning down non-sandboxed apps?
For your first question, no, I don't believe there is any way to write to a file the user didn't specify, unless it's either in your app's container, or (as of 10.7.3) in a directory you have a security-scoped URL for. See the documentation here. If the user specifies a file, I doubt you get permissions to the enclosing folder, but it's worth a shot.
Answering your second question, as of today, Friday April 27th, 2012, the App Store does not require sandboxing. The latest deadline given was June 1, 2012.

Resources