I have an app that shares files between users of the app by attaching the file to either an email or an iMessage. The original implementation attached a JSON file but I was able to build a smaller binary file, allowing me to have more content within the file size limit. Mail attachments work just fine.
I've modified the info plist to define the app-specific file extension. But no matter where I define it, iMessage refuses to put up a preview where the user can select my app to open it. I tried putting it in a document type with a public.text, public.data roles. I tried adding it to the Exported Type Identifiers as a public-mime-type.
I made sure the identifiers all have the reverse url com.<company>.<appname>.<file extension>
My temporary iMessage workaround is to name the file with .zip, a known public extension. It doesn't have valid zip data, it just declares it as a zip file and allows the user to pick my app to open it because I added zip as an exported type identifier. But I don't want the user to think my app can also open zip files.
I would be happy if the preview looked similar to what is done for zip files - a file icon, but with my app's name inside the icon.
Any help with this configuration nightmare is appreciated. Mike
Thanks for the detailed write-up, and apologies this sat unanswered. Since a second developer is seeing the same thing, I built a small test here to determine what is and isn't possible. The results explain the behavior.
First, the declaration itself. For a binary format, the exported type needs to conform to public.data. A type that doesn't conform to public.data can't be identified as a stored item. Conform to public.content as well, so the type participates in sharing. Declaring the type as public.text is the wrong base for binary data. The file extension and MIME type belong inside the type's UTTypeTagSpecification, under public.filename-extension and public.mime-type. They are tags on your type, not a role the identifier itself takes on. A correct exported declaration looks like this:
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>com.yourcompany.yourapp.gadget</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Gadget Document</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>gadget</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-gadget</string>
</array>
</dict>
</dict>
</array>
The app also claims the type as a document type it handles, through CFBundleDocumentTypes, with LSItemContentTypes set to your identifier. In modern code you work with these types through the UniformTypeIdentifiers framework and its UTType type.
With that in place, here is what I measured. I declared a custom binary type, wrote a file, and sent it through Messages to two devices:
- On a device with the app installed, the attachment showed the type's description next to the filename, so the type is recognized.
- On a device without the app installed, the same attachment showed only the filename and the byte count, with no type name and no custom icon.
That second result is the key one, and it explains what you are seeing. An exported type declaration lives inside your app's bundle, so the system knows the type only on devices where your app is installed. When you email or message the file to someone who doesn't have your app, their device has no declaration for your extension. It shows the file as filename and size only. Nothing you configure in the app changes how the file appears on a device that doesn't have it. The description of the type is not present there.
This is also why renaming to .zip changes the result. public.zip-archive is a system type that every device already knows, so it renders with a recognized icon everywhere. The cost is that it's no longer your own type.
So the realistic options depend on the recipient:
- If recipients have your app, for example sharing among your own customers, a correct declaration gives you the recognized type name. To replace the generic document glyph with a custom image, a QuickLook Thumbnail Extension is the documented mechanism. The system uses it to show thumbnails of custom files across the operating system and other apps, again only where your app is installed.
- If the files go to people who may not have your app, there is no way to present a branded icon or name to them. A widely recognized container or format, as you found with
.zip, is the way to get a consistent presentation on every device.
A correct declaration gets the type recognized on devices that have your app, and there is no equivalent for devices that don't. That follows from custom types being declared inside the app, rather than being a setting to adjust.
For reference: