Monday, September 24, 2012

Uniform Type Identifiers on OS X


Before OS X 10.4, OS X used File Types and Creator Codes to identify documents created by applications.  Since then Apple has been phasing out Creator Codes and File Types.  It now recommends that you use a Uniform Type Identifier (UTI) to identify documents.

A UTI is a special text string that identifies both data and application documents.  For example, the UTI for a PNG picture is public.PNG.

You would use the same UTI for a PNG file.

If you are working with common file types, you should use the public UTI for it.

Here are some links for reference:
Note: UTIs work with both Cocoa and Carbon applications.

Custom UTI

For your own documents, you can create your own UTI.  A custom UTI typically has a “reverse-domain name” format plus an additional entry for the document type name.  So you might have a UTI such as “com.company.app.doc”.  The first part of this UTI must match the Application Identifier specified in the App properties (com.company.app in this case).

You create a UTI for your documents using the File Type editor.  The last column in the editor lets you specify the UTI.

When you build your application, the UTI information is included in the Info.plist file in the application bundle.  But in order for this to work properly, you have to add an additional “UTExportedTypeDeclaration” section to the plist manually.

Setting up a Custom UTI

These are the steps to create a custom document type that can be opened by your application. You need to do these steps after each build of your application because the Info.plist that you need to modify is recreated with each build:
  1. In the App Properties, set these values:
    • Specify the application identifier for your application using reverse domain name format: com.company.app
    • Enter “????” as the MacCreator. This is simply a placeholder; it is not used.
  2. Add a File Types Set to your project.
    • Enter a name for Display Name and Object Name (such as MyCustomDocType).
    • Enter “????” for MacType and MacCreator. These are placeholders and are not used.
    • Specify your extension (without a period).
    • Enter the UTI using your application identifier as the base.  For example, this could be your doc UTI: com.company.app.doc
    • Choose the icon to use to identify files of this type.
  3. Go back to the App Properties and set this value:
    • Specify your File Type in AcceptFileTypes
  4. Build your application.
  5. In Finder, go to your application and select “Show Package Contents” from the contextual menu.  Navigate to the Contents folder and open Info.plist file in a text editor.  Add the following code to the end (before </dict>), replacing the UTI (com.company.app.doc) and extension (myextension) as appropriate:
    • <key>UTExportedTypeDeclarations</key>
        <array>
          <dict>
            <key>UTTypeConformsTo</key>
            <array>
              <string>public.data</string>
              <string>public.item</string>
            </array>
            <key>UTTypeIdentifier</key>
            <string>com.company.app.doc</string>
            <key>UTTypeTagSpecification</key>
            <dict>
              <key>
      public.filename-extension</key>
              <array>
                <string>
      myextension</string>
              </array>
            </dict>
          </dict>
        </array>
  6. Save Info.plist
  7. Navigate back to the your application in the Finder and Run your application to register the types
When you use GetSaveFolderItem (or SaveAsDialog), you supply the FileType to use as the Filter.  A custom document created with the selected file will be associated with your application so that the specified icon appears and so it can be opened by your application.

Dim f As Folderitem
f = GetSaveFolderItem(FileTypes1.CustomType, "Untitled" + FileTypes1.CustomType.Extensions)

If f <> Nil Then
  Dim output As BinaryStream
  output = BinaryStream.Create(f, True)
  output.Write("CustomType: Sample Text")
  output.Close
End If

When you view the saved document in the Finder, you will see that it has the specified icon.  Double-clicking it will launch your app (if it is not already launched) and call the OpenFile event.

Opening files works by supplying the name of your FileType as the filter of an open dialog:

Dim f As FolderItem
f = GetOpenFolderItem(FileTypes1.MyType)


Migrating to UTIs from MacCreator and MacType

If you have been using the MacCreator and MacType properties of a FolderItem and specifying them in File Type Sets, then you need to start using UTIs soon.  Apple has deprecated both MacCreator and MacType.

To switch to using UTIs, you simply need to start using UTIs in your File Type Sets and updating Info.plist as described earlier.  You can leave the old MacCreator and MacType setting in place or you can remove them so that you do not get deprecation warnings when analyzing your projects.

6 comments:

Anic297 said...

When you say “Note: UTIs work with both Cocoa and Carbon applications.”, how could it be otherwise?
The LaunchServices component doesn't (and couldn't) take care of what type the target application is.

Paul Lefebvre said...

You are correct, it could not be otherwise. But, sometimes something that may seem obvious to some has to be plainly stated for the benefits of others.

Beatrix Willius said...

You said: You create a UTI for your documents using the File Type editor. The last column in the editor lets you specify the UTI.

But this doesn't work. There is an ages old feature request/bug about this:

Paul Lefebvre said...

@Beatrix: What doesn't work? In the UTI's column of the File Type Sets Editor you can type in the UTI value for the file type.

Stan Busk said...

Shouldn't RealStudio do that automatically? The problem here is that I have automated builds with a script... how can I do that from the script?

Tom said...

Thank you a thousand times for this article. I have read all the forum discussions and could never get this to work. I went through this article step by step and it works perfectly.
Can't REAL Software put the needed lines in the info.plist when compiling?