Associating file extension with my application

My application uses a text file with an extension of .dssfilelist. On Linux I would register the Mime type and associate it with the application in the .desktop file.

<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
    <mime-type type="text/dssfilelist">
        <comment>DeepSkyStacker file-list file</comment>
        <glob pattern="*.dssfilelist" />
    </mime-type>
</mime-info>

I believe that I need to add stuff to the Info.plist for my application, but I also understand that CFBundleTypeExtensions is deprecated.

So please could you show me what I now need to add to the Info.plist file so that these files will be registered as "text/dssfilelist" type and associated with my application and to associate a .icns file with it?

Answered by DTS Engineer in 838587022

The best way to deal with this is in Xcode. Specifically, if you bring up the target editor for an app target, the Info tab has slices labelled Document Types, Exported Type Identifiers, and Imported Type Identifiers.

My advice above still stands even if you’re not using Xcode. In that case I recommend that you use Xcode to set things up how you want them, then look at the resulting Info.plist to see what it did.

Another good trick is to look at how other apps do this. I’ve included an example of that below.

Current documentation for this stuff is in Bundle Resources > Information Property List > Data and storage. That’s very… well… focused, which is why I tend to lean into Xcode. If you’re looking for more conceptual stuff, the legacy docs are generally OK. This stuff hasn’t changed significantly since it was introduced.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"


% plutil -p /Applications/Pages.app/Contents/Info.plist          
{
  …
  "CFBundleDocumentTypes" => [
    0 => {
      "CFBundleTypeName" => "com.apple.iwork.pages.document"
      "CFBundleTypeRole" => "Editor"
      "LSDefaultShareModeCollaboration" => 1
      "LSHandlerRank" => "Owner"
      "LSItemContentTypes" => [
        0 => "com.apple.iwork.pages.pages"
      ]
      "NSDocumentClass" => "TPMacDocument"
      "NSDownloadsUbiquitousContents" => 1
      "NSIsRelatedItemType" => 1
      "NSUbiquitousDocumentUserActivityType" => "com.apple.pages.documentEditing"
    }
    …
  ]
  …
  "UTExportedTypeDeclarations" => [
    0 => {
      "UTTypeConformsTo" => [
        0 => "com.apple.package"
        1 => "public.composite-content"
      ]
      "UTTypeDescription" => "Pages Document"
      "UTTypeIcons" => {
        "UTTypeIconText" => "PAGES"
      }
      "UTTypeIdentifier" => "com.apple.iwork.pages.pages-tef"
      "UTTypeTagSpecification" => {
        "public.filename-extension" => [
          0 => "pages-tef"
        ]
      }
    }
    …
  ]
  "UTImportedTypeDeclarations" => [
    0 => {
      "UTTypeConformsTo" => [
        0 => "public.data"
        1 => "public.composite-content"
      ]
      "UTTypeDescription" => "Microsoft Word Macro-Enabled template"
      "UTTypeIdentifier" => "org.openxmlformats.wordprocessingml.template.macro-enabled"
      "UTTypeTagSpecification" => {
        "com.apple.ostype" => [
          0 => "DOTM"
        ]
        "public.filename-extension" => [
          0 => "dotm"
        ]
      }
    }
    …
  ]
}

Here's what filesays:

amonra@Saturn ~ % cd /Applications/DeepSkyStacker.app/Contents/Resources
amonra@Saturn Resources % file DSS_filelist.icns
DSS_filelist.icns: Mac OS X icon, 1291846 bytes, "ic12" type
amonra@Saturn Resources % 

I just noticed something interesting which might suggest my Info.plist isn't incorrect! If I set finder into "View as list" mode, then the .dssfilelist files DO show the correct icon:

However if Finder is set to "View as Icons" then they just show a an Icon that looks like it might be the file contents:

:(

Is that what I should expect to see? I had rather assumed I'd be shown the Icon when using "View as Icons".

David

I had some time to work through this in depth today. As a reminder, my golden rule for this sort of thing is to do what Xcode does. So, I started out by creating a new Xcode project that works. Here’s what I did:

  1. Using Xcode 16.3 on macOS 15.4, I created a new project, named Test783646, from the macOS > Document App template.

  2. That has an asset catalogue, Assets.xcassets, that has an AppIcon placeholder. I filled that out with all the sizes.

  3. At the bottom left of the asset catalogue editor there’s a plus (+) button. I clicked that and chose macOS > macOS Generic Icon.

  4. I named that DocIcon and filled in all the sizes.

  5. I edited the Info.plist file to look like that shown at the end of this post. There’s a bunch of important changes here:

    • I switched from UTImportedTypeDeclarations to UTExportedTypeDeclarations. That’s necessary because I want to define a new file type. The document app template imports public.plain-text and uses that as its file type.

    • I set the content type to be a unique value, com.example.apple-samplecode.Test783646.doc.

    • I conformed that to public.content and public.data, for reasons I explained above.

    • I added .test783646doc as its extension.

    • And DocIcon as its icon.

    • And set the description.

  6. In Test783646Document.swift, I change the exampleText property to be my document type, that is, com.example.apple-samplecode.Test783646.doc.

  7. In the target editor, I changed the deployment target to macOS 15.0.

  8. I built the app.

The app structure now looks like this:

% find Test783646.app 
Test783646.app
Test783646.app/Contents
Test783646.app/Contents/_CodeSignature
Test783646.app/Contents/_CodeSignature/CodeResources
Test783646.app/Contents/MacOS
Test783646.app/Contents/MacOS/Test783646
Test783646.app/Contents/MacOS/__preview.dylib
Test783646.app/Contents/MacOS/Test783646.debug.dylib
Test783646.app/Contents/Resources
Test783646.app/Contents/Resources/AppIcon.icns
Test783646.app/Contents/Resources/Assets.car
Test783646.app/Contents/Info.plist
Test783646.app/Contents/PkgInfo

Xcode has unpacked AppIcon because that’s a strict requirement. It’s left DocIcon in the asset catalogue because that placement is compatible with my deployment target.


I then tested the app:

  1. I restored a macOS 15.3.2 VM to a clean snapshot. Note that there’s nothing special about that version number; it’s just what I have lying around.

  2. I copied the app to the VM using scp.

  3. In the VM, I see that the app has the right icon.

  4. I launched the app and saved a new document to disk. It has the right document icon.


Now, I realise that you don’t want to use an asset catalogue, so I rebuilt the app to use a .icns:

  1. I extract a .iconset from the asset catalogue of the built app:

    % iconutil -c iconset -o DocIcon.iconset Test783646.app/Contents/Resources/Assets.car DocIcon
    

    I could’ve built this .iconset manually, but extracting it was easier (-:

  2. In Xcode, I removed DocIcon from the asset catalogue.

  3. And added the DocIcon.iconset that I created in step 1.

  4. I built the app.

Now the built app looks like this:

% find Test783646.app 
Test783646.app
…
Test783646.app/Contents/Resources/DocIcon.icns
Test783646.app/Contents/Resources/AppIcon.icns
…

And there’s no sign of DocIcon in the asset catalogue:

% assetutil -I Test783646.app/Contents/Resources/Assets.car | grep DocIcon
% 

I then repeated my test process and confirmed that the doc icon still works.

IMPORTANT Note how the test process involves restoring my VM from a fresh snapshot, so I’m 100% sure that my first test run won’t interfere with the second.


So, in summary, in the built app, I have this:

% find Test783646.app 
Test783646.app
…
Test783646.app/Contents/Resources/DocIcon.icns
Test783646.app/Contents/Resources/AppIcon.icns
…
% file Test783646.app/Contents/Resources/DocIcon.icns
Test783646.app/Contents/Resources/DocIcon.icns: Mac OS X icon, 37195 bytes, "ic12" type

and this:

% plutil -p Test783646.app/Contents/Info.plist 
{
  …
  "CFBundleDocumentTypes" => [
    0 => {
      "CFBundleTypeRole" => "Editor"
      "LSHandlerRank" => "Default"
      "LSItemContentTypes" => [
        0 => "com.example.apple-samplecode.Test783646.doc"
      ]
      "NSUbiquitousDocumentUserActivityType" => "com.example.apple-samplecode.Test783646.exampledocument"
    }
  ]
  …
  "UTExportedTypeDeclarations" => [
    0 => {
      "UTTypeConformsTo" => [
        0 => "public.content"
        1 => "public.data"
      ]
      "UTTypeDescription" => "Test783646 document"
      "UTTypeIconFile" => "DocIcon"
      "UTTypeIdentifier" => "com.example.apple-samplecode.Test783646.doc"
      "UTTypeTagSpecification" => {
        "public.filename-extension" => [
          0 => "test783646doc"
        ]
      }
    }
  ]
}

I think this should be enough to get you on track, but let me know otherwise.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

<?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>CFBundleDocumentTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>LSHandlerRank</key>
			<string>Default</string>
			<key>LSItemContentTypes</key>
			<array>
				<string>com.example.apple-samplecode.Test783646.doc</string>
			</array>
			<key>NSUbiquitousDocumentUserActivityType</key>
			<string>$(PRODUCT_BUNDLE_IDENTIFIER).exampledocument</string>
		</dict>
	</array>
	<key>UTExportedTypeDeclarations</key>
	<array>
		<dict>
			<key>UTTypeConformsTo</key>
			<array>
				<string>public.content</string>
				<string>public.data</string>
			</array>
			<key>UTTypeDescription</key>
			<string>Test783646 document</string>
			<key>UTTypeIconFile</key>
			<string>DocIcon</string>
			<key>UTTypeIdentifier</key>
			<string>com.example.apple-samplecode.Test783646.doc</string>
			<key>UTTypeTagSpecification</key>
			<dict>
				<key>public.filename-extension</key>
				<array>
					<string>test783646doc</string>
				</array>
			</dict>
		</dict>
	</array>
</dict>
</plist>

I changed one thing in my Info.plist and now it works as I expected.

I changed this:

			<key>UTTypeConformsTo</key>
			<array>
				<string>public.plain-text</string>

to

			<key>UTTypeConformsTo</key>
			<array>
				<string>public.data</string>

Now the Icon view in Finder shows the Icon I want instead of an icon it builds itself from the content of the text file.

Thanks again for your assistance David

Associating file extension with my application
 
 
Q