Search code examples
c++macosfile-associationdmg

macOS application file association


I have been trying to sift through information for a while now, and I am having issues determining what is still still relevant. It also seems that for some reason there is less info on the subject than there should be.

I am working on an application that is distributed for macOS. I would like to associate a custom file extension with my application. I would like the user to be able to double click on one of the files and have the application open it. Its easy enough for me to pick the application to open the files, but I cant figure out how to get the filename for the opened file.

The only thing I have found so far is to create an application from an AppleScript. Then the AppleScript can parse the arguments and call the main application with them. I have two problems with this approach.

First, what happens if the user changes it and selects the application directly? I supposed it just wont work? Is there any way around that?

Second, how do I associate the application automatically in the first place? I found information about CFBundleTypeExtensions, but then later found that this was deprecated. I found some info on UTI's and Launch Services. It makes sense how to add a UTI to the plist file and run the lsregister command. How would you do this automatically though? The user installs the application using a dmg, at what point can I run the lsregister command?


Solution

  • Add something like the following to your Info.plist. It will tell macOS that your application handles .foo and .bar files.

    <key>CFBundleDocumentTypes</key>
    <array>
    <dict>
        <key>CFBundleTypeRole</key>
            <string>Viewer</string>
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>foo</string>
            <string>bar</string>
        </array>
        <key>CFBundleTypeIconFile</key>
            <string>FileIcons.icns</string>
        <key>CFBundleTypeMIMETypes</key>
            <string>application/octet-stream</string>
        <key>CFBundleTypeName</key>
            <string>Something Unique Here</string>
        <key>CFBundleTypeOSTypes</key>
        <array>
            <string>****</string>
        </array>
    </dict>
    </array>
    

    FileIcons.icns should contain the icon files for the registered files. If you don't want to create file icons, you can leave that string empty:

    <key>CFBundleTypeIconFile</key>
        <string></string>
    

    CFBundleTypeMIMETypes is set to application/octet-stream above. That's the MIME type for generic binary data. If the files actually have proper MIME types, then use those.

    Once macOS sees your app (when downloading it for example,) it will automatically know to open .foo and .bar. You don't need to run anything external.

    Finally, your application will be launched by macOS when the user double-clicks a .foo or .bar file, and it will receive an "open file" event. You need to handle that. How you do that depends on what framework/language you use to develop your app.