Introduction
I recently came across a situation where I needed the ability to share data between users of the same iOS application. Unfortunately, these users can not share an iCloud account and there is no server side components to this application. It is a standalone app. Services like DropBox were not really an option either, as the devices are owned by an enterprise and will not have any service like that deployed onto them.
One solution is importing data via custom file types. Files can be sent to a device numerous ways (e.g. email, drop box, etc.), but for this post we will assume email. iOS makes it very simple to define a custom file type that your app can handle. This way, when the device receives an email with that type as an attachment, the user can select our app, giving it access to the underlying file. This post will walk through creating a simple app to access the contents of a text file received via email.
Create the Project
Lets start by creating a new project in XCode. I created a single view iPad application and called it “CustomUTIHandler”. I always use ARC. You can choose to use storyboards or not, as the UI in this app will do nothing more than display the contents of our file. The resulting project for this post can be found at https://github.com/stevenpsmith/CustomFileHandler.
Define the File Type
The next thing is to define a file type extension that our application will support. This is also known as a Uniform Type Identifier (UTI). For our purpose, we will use a filetype of ‘csm’ (for Chariot Solutions Mobile). The contents of this file will be some string. It could really be almost anything, but for simplicity we will use a string.
For a list of Apple defined UTIs, look here: http://developer.apple.com/library/ios/#documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html#//apple_ref/doc/uid/TP40009259-SW1.
Once we know what our custom file type extension is, we can add support for it to the project by modifying the Info.plist file for the project. We are going to be the owner/exporter of the new file type, so we add the “Exported Type UTIs” key to the Info.plist file. The default definition that gets created looks like this (click to expand):
Based on the bundle key definitions found in https://developer.apple.com/…/CocoaKeys.html, we can fill in the required values. Since our example only has one file type that it is defining and the underlying data is text, we can add the system defined identifier for text to the “Conforms to UITs” item: public.text.
Next we need to add the identifier for our custom UTI. Apple recommends using the reverse DNS format in order to ensure our new UTI is unique. I will be using the following:
com.chariotsolutions.customUTIHandler.csm
Finally, we want to identify the file extension that our app will be handling. This is defined under the “Equivalent Types” node. Add a node under the equivalent types with a name of “public.filename-extension” and a value of “csm”. You can optionally add a “Description” element under the Item for the exported type. My Info.plist now looks like this (click to expand):
Support our new File Type
In order for our app to be recognized by the OS as supporting the newly defined file type, we need to add a “Document types” declaration to our Info.plist file. Doing so gives us the following in our Info.plist file (click to expand):
The possible keys for the CFBundleDocumentTypes property can be found at http://developer.apple.com/library/…/CoreFoundationKeys.html…. We can add anything for the “Document Type Name” value. The handler rank will affect the order that Launch Services uses to present apps that handle this file type. Since our app is really the owner of this file type, we will use that as the handler rank.
Now we need to add the “Document Content Type UITs” that our app will handle. In this case, we are only handling one type (as defined in the export key above):
com.chariotsolutions.customUTIHandler.csm
Just for fun, we will also give our file type an image icon (included in the project). The specs for the image are defined in the keys document referenced above (64×64 in this case). So our final Info.plist looks like the following (click to expand):
Now all we have to do is create a text file with a “.csm” extension and email it to our device. Once there, long press the resulting icon and we should see our app listed as one of the “Open in” apps.
Once we select our app, it will launch and pass the file URL to this app delegate method:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
So, adding a simple NSLog statement to the method and we can display the contents of our text file:
- (BOOL) application:(UIApplication *)application openURL:(NSURL *) url sourceApplication:(NSString *) sourceApplication annotation:(id) annotation { if (url) { NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSLog(@"The file contained: %@",str); } return YES; }
Important Safety Tip
The files that are being opened by the application are actually copied into a directory called “Inbox” within the apps Documents directory. My file was called “This is a test.csm” (great name right, what am I a windows user?). As shown in the image below, there are copies for each time I imported it on my device.
These files should be cleaned up as required by your app.
Summary
So by adding some configuration to our apps Info.plist file and implementing a delegate method, we can handle any uniform types within our app. The source code for this project can be found at https://github.com/stevenpsmith/CustomFileHandler. I added some code so that it will display the contents of the file on the screen….very exciting.
Added Bonus
Since we are declaring to launch services that our app handles “csm” files, drop your custom file type into drop box. Assuming you have the drop box app on you device, find the document in the app and try to open it. You should get “Unable to view file”. But if you tap the icon in the upper right of the screen, you should get a list of apps that can open that file….including our app.
It’s like magic 🙂 You see those other apps listed because we defined our UTI as text type, and those apps will handle text documents.