How do I associate file types with an iPhone application?
Asked Answered
G

5

330

On the subject of associating your iPhone app with file types.

In this informative question I learned that apps could be associated with custom URL protocols.

That was almost one year ago and since then Apple introduced 'Document Support' which goes a step further and allows apps to associate with file types. There is a lot of talk in the documentation about how to set up your app to launch other appropriate apps when it encounters an unknown file type. This means the association doesn't work out of the box for any app, like the URL protocol registering did.

This leads me to the question: have system apps like Safari or Mail implemented this system for choosing associated applications, or will they do nothing, as before?

Guardrail answered 5/5, 2010 at 14:59 Comment(0)
N
416

File type handling is new with iPhone OS 3.2, and is different than the already-existing custom URL schemes. You can register your application to handle particular document types, and any application that uses a document controller can hand off processing of these documents to your own application.

For example, my application Molecules (for which the source code is available) handles the .pdb and .pdb.gz file types, if received via email or in another supported application.

To register support, you will need to have something like the following in your Info.plist:

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeIconFiles</key>
        <array>
            <string>Document-molecules-320.png</string>
            <string>Document-molecules-64.png</string>
        </array>
        <key>CFBundleTypeName</key>
        <string>Molecules Structure File</string>
        <key>CFBundleTypeRole</key>
        <string>Viewer</string>
        <key>LSHandlerRank</key>
        <string>Owner</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.sunsetlakesoftware.molecules.pdb</string>
            <string>org.gnu.gnu-zip-archive</string>
        </array>
    </dict>
</array>

Two images are provided that will be used as icons for the supported types in Mail and other applications capable of showing documents. The LSItemContentTypes key lets you provide an array of Uniform Type Identifiers (UTIs) that your application can open. For a list of system-defined UTIs, see Apple's Uniform Type Identifiers Reference. Even more detail on UTIs can be found in Apple's Uniform Type Identifiers Overview. Those guides reside in the Mac developer center, because this capability has been ported across from the Mac.

One of the UTIs used in the above example was system-defined, but the other was an application-specific UTI. The application-specific UTI will need to be exported so that other applications on the system can be made aware of it. To do this, you would add a section to your Info.plist like the following:

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.plain-text</string>
            <string>public.text</string>
        </array>
        <key>UTTypeDescription</key>
        <string>Molecules Structure File</string>
        <key>UTTypeIdentifier</key>
        <string>com.sunsetlakesoftware.molecules.pdb</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <string>pdb</string>
            <key>public.mime-type</key>
            <string>chemical/x-pdb</string>
        </dict>
    </dict>
</array>

This particular example exports the com.sunsetlakesoftware.molecules.pdb UTI with the .pdb file extension, corresponding to the MIME type chemical/x-pdb.

With this in place, your application will be able to handle documents attached to emails or from other applications on the system. In Mail, you can tap-and-hold to bring up a list of applications that can open a particular attachment.

When the attachment is opened, your application will be started and you will need to handle the processing of this file in your -application:didFinishLaunchingWithOptions: application delegate method. It appears that files loaded in this manner from Mail are copied into your application's Documents directory under a subdirectory corresponding to what email box they arrived in. You can get the URL for this file within the application delegate method using code like the following:

NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];

Note that this is the same approach we used for handling custom URL schemes. You can separate the file URLs from others by using code like the following:

if ([url isFileURL])
{
    // Handle file being passed in
}
else
{
    // Handle custom URL scheme
}
Narcolepsy answered 6/5, 2010 at 13:5 Comment(18)
I'm not able to try this on the iPad/iPhone simulator. I have downloaded the molecules application and Safari cannot open .pdb or even .gz files as the Info.plist claims. It simply says, "Safari cannot download the file"Sneakbox
@Sneakbox - Yes, there is a bug in the application involving how it downloads PDBs located on certain servers that I haven't quite tracked down yet. That is independent of the file handling and custom URL schemes, though.Narcolepsy
@Brad - Excellent answer - thank you. I followed your instruction as I'm trying to register an application that will open png and jpeg files, alas I couldn't get mail to show an open in... option for these attachment in mail. Is it possible to take the same approach and have mail open images in my app?Fidel
@Brad Larson--> i will get the url of pdf file.I want to save the pdf file to documents directory.How can i do that?Stagecraft
@Stagecraft - All you need to do is move the file at the URL that has been passed in to your application's Documents directory. I believe that it is automatically copied to a subdirectory in your Documents directory anyway, so you just need to move it to the root of the Documents directory and delete the old temporary subdirectory. I do this in my Molecules application, so you can look at the code I use for this.Narcolepsy
@nacho4d - Did you change the UTI in both places? Did you remove the org.gnu.gnu-zip-archive UTI? Did you change the UTTypeConformsTo to match that for a property list? Did you change the extension and MIME type? All of that needs to be customized for your particular case, and all references to the items I have in there need to be removed. The best reference for this are the two articles I link to above.Narcolepsy
@Brad Thanks, I actually could do it after reading "iPad development for iPhone developers" and my answer plist is here: stackoverflow.com/questions/3827558/…Chary
I just realized that when I attach my .mndl file to a mail using MFMailComposeViewController the attachment does not show the icon it's supposed to inside this MFMailComposerViewController, but it shows correctly in Mail.app. Is this because I didn't wrote the mime type in UTTypeTagSpecification array? If yes, what should I write? (.mndl files are a particular case of .plist I have created.) I would appreciate your help. ThanksChary
It should be noted that -application:didFinishLaunchingWithOptions: in the app delegate is only called if your app was not backgrounded when it's opened to handle a file.Catheterize
Instructions work perfectly, but: How do you avoid Mail wanting to open attachments for your app in QuickLook? https://mcmap.net/q/24044/-mime-type-or-something-so-ios-mail-does-not-open-in-quicklook/8047Focal
Avoiding QuickLook: raywenderlich.com/1980/…Alto
brad do you mind looking at: stackoverflow.com/questions/9434574/… I'm having a lot of trouble understanding what to put for the public.mime-type keyUnnerve
To disable the QuickLook in Mail, set the UTTypeConformsTo to an array with a single "public/data" element.Rout
We should use - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url also on iOS 4+Campobello
@BradLarson: Hi any success with Image type file? I've tried stackoverflow.com/questions/9197757/… but didn't worked. My app doesn't show in list from Image Gallery !Aeneid
What about the key 'CFBundleTypeExtensions'? Your snippet does not seem to set it. Is it not required?Mneme
I have tried all the methodology provided here and other places as well, but I am still struggling to get open PNG files. I am working with iOS 7. In some places they are saying that this problem starts with ios 6. Is it true? Can't we open png files in "Open in " dialog box with ios 7?Denice
Be sure to check which plist file your app is using, so that your edits take effect. In Xcode, go to TargetsBuild SettingsInfo.plist File to determine which file to edit.Grivation
M
24

In addition to Brad's excellent answer, I have found out that (on iOS 4.2.1 at least) when opening custom files from the Mail app, your app is not fired or notified if the attachment has been opened before. The "open with…" popup appears, but just does nothing.

This seems to be fixed by (re)moving the file from the Inbox directory. A safe approach seems to be to both (re)move the file as it is opened (in -(BOOL)application:openURL:sourceApplication:annotation:) as well as going through the Documents/Inbox directory, removing all items, e.g. in applicationDidBecomeActive:. That last catch-all may be needed to get the app in a clean state again, in case a previous import causes a crash or is interrupted.

Mesoblast answered 26/6, 2011 at 12:31 Comment(2)
I don't see this behavior. If my app is backgrounded, -(BOOL)application:openURL:sourceApplication:annotation: is always called, even for attachments that have been already opened. Each additional time the attachment is opened, a number is suffixed to the filename and is incremented to be unique -- test.text, test-1.txt, test-2.txt, etc.Catheterize
My Inbox directory is empty, but yet I have the unresponsive "Open In" button in Safari you speak of. Years ago, my app was working fine, but suddenly it stopped working. I suspect Apple changed something in Safari.Mneme
P
19

BIG WARNING: Make ONE HUNDRED PERCENT sure that your extension is not already tied to some mime type.

We used the extension '.icz' for our custom files for, basically, ever, and Safari just never would let you open them saying "Safari cannot open this file." no matter what we did or tried with the UT stuff above.

Eventually I realized that there are some UT* C functions you can use to explore various things, and while .icz gives the right answer (our app):

In app did load at top, just do this...

NSString * UTI = (NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, 
                                                                   (CFStringRef)@"icz", 
                                                                   NULL);
CFURLRef ur =UTTypeCopyDeclaringBundleURL(UTI);

and put break after that line and see what UTI and ur are -- in our case, it was our identifier as we wanted), and the bundle url (ur) was pointing to our app's folder.

But the MIME type that Dropbox gives us back for our link, which you can check by doing e.g.

$ curl -D headers THEURLGOESHERE > /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 27393  100 27393    0     0  24983      0  0:00:01  0:00:01 --:--:-- 28926
$ cat headers
HTTP/1.1 200 OK
accept-ranges: bytes
cache-control: max-age=0
content-disposition: attachment; filename="123.icz"
Content-Type: text/calendar
Date: Fri, 24 May 2013 17:41:28 GMT
etag: 872926d
pragma: public
Server: nginx
x-dropbox-request-id: 13bd327248d90fde
X-RequestId: bf9adc56934eff0bfb68a01d526eba1f
x-server-response-time: 379
Content-Length: 27393
Connection: keep-alive

The Content-Type is what we want. Dropbox claims this is a text/calendar entry. Great. But in my case, I've ALREADY TRIED PUTTING text/calendar into my app's mime types, and it still doesn't work. Instead, when I try to get the UTI and bundle url for the text/calendar mimetype,

NSString * UTI = (NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
                                                                   (CFStringRef)@"text/calendar", 
                                                                   NULL);

CFURLRef ur =UTTypeCopyDeclaringBundleURL(UTI);

I see "com.apple.ical.ics" as the UTI and ".../MobileCoreTypes.bundle/" as the bundle URL. Not our app, but Apple. So I try putting com.apple.ical.ics into the LSItemContentTypes alongside my own, and into UTConformsTo in the export, but no go.

So basically, if Apple thinks they want to at some point handle some form of file type (that could be created 10 years after your app is live, mind you), you will have to change extension cause they'll simply not let you handle the file type.

Pape answered 24/5, 2013 at 17:57 Comment(1)
Thanks for the useful warning!Neurology
E
1

To deal with any type of files for my own APP, I use this configuration for CFBundleDocumentTypes:

    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeName</key>
            <string>IPA</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.item</string>
                <string>public.content</string>
                <string>public.data</string>
                <string>public.database</string>
                <string>public.composite-content</string>
                <string>public.contact</string>
                <string>public.archive</string>
                <string>public.url-name</string>
                <string>public.text</string>
                <string>public.plain-text</string>
                <string>public.source-code</string>
                <string>public.executable</string>
                <string>public.script</string>
                <string>public.shell-script</string>
                <string>public.xml</string>
                <string>public.symlink</string>
                <string>org.gnu.gnu-zip-archve</string>
                <string>org.gnu.gnu-tar-archive</string>
                <string>public.image</string>
                <string>public.movie</string>
                <string>public.audiovisual-​content</string>
                <string>public.audio</string>
                <string>public.directory</string>
                <string>public.folder</string>
                <string>com.apple.bundle</string>
                <string>com.apple.package</string>
                <string>com.apple.plugin</string>
                <string>com.apple.application-​bundle</string>
                <string>com.pkware.zip-archive</string>
                <string>public.filename-extension</string>
                <string>public.mime-type</string>
                <string>com.apple.ostype</string>
                <string>com.apple.nspboard-typ</string>
                <string>com.adobe.pdf</string>
                <string>com.adobe.postscript</string>
                <string>com.adobe.encapsulated-​postscript</string>
                <string>com.adobe.photoshop-​image</string>
                <string>com.adobe.illustrator.ai-​image</string>
                <string>com.compuserve.gif</string>
                <string>com.microsoft.word.doc</string>
                <string>com.microsoft.excel.xls</string>
                <string>com.microsoft.powerpoint.​ppt</string>
                <string>com.microsoft.waveform-​audio</string>
                <string>com.microsoft.advanced-​systems-format</string>
                <string>com.microsoft.advanced-​stream-redirector</string>
                <string>com.microsoft.windows-​media-wmv</string>
                <string>com.microsoft.windows-​media-wmp</string>
                <string>com.microsoft.windows-​media-wma</string>
                <string>com.apple.keynote.key</string>
                <string>com.apple.keynote.kth</string>
                <string>com.truevision.tga-image</string>
            </array>
            <key>CFBundleTypeIconFiles</key>
            <array>
                <string>Icon-76@2x</string>
            </array>
        </dict>
    </array>
Emblazonment answered 20/10, 2019 at 23:32 Comment(1)
What could be the "LSItemContentTypes" for TIFF file? Could you please help!Margarettemargarida
O
0

Install duti. It's the most complete and serious solution to instantly bind UTIs to Appls. You have it here: duti on GitHub

If you prefer something with Graphic Interface: SwiftDefaultApps on GitHub

Optician answered 5/11, 2022 at 10:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.