Sandboxing on iOS makes the platform much more secure and this ultimately benefits every user of the platform. However, because of the strict rules inherent to sandboxing, sharing data between applications is not trivial. An often overlooked class that helps with sharing documents between applications is the UIDocumentInteractionController
class. In this quick tip, I will show you how you can use this class to preview documents as well as opening documents in other applications installed on the device.
Interacting with Documents
I must admit that I was a little surprised to discover that UIDocumentInteractionController
has been with us since iOS 3.2. The UIDocumentInteractionController
class is flexible in its use and more powerful than most of us realize. Not only does it allow developers to open documents in other applications installed on the device, it also supports previewing, printing, emailing, and copying of documents.
Using the UIDocumentInteractionController
class is straightforward. The first step is to initialize an instance of the class by invoking its sole class method, interactionControllerWithURL:
, and passing the URL (NSURL
) of the document that you intend to work with. After setting the document interaction controller's delegate property, you implement the appropriate delegate methods.
Keep in mind that the UIDocumentInteractionController
is not a subclass of UIViewController
. In other words, even though previewing a document is mediated by the UIDocumentInteractionController
, you have to tell the document interaction controller which view controller to use for previewing the document. What this exactly means will become clear when we build the sample application. In the sample application, I will show you how to (1) preview a document and (2) open a document in another application that supports the document's file type.
Step 1: Setting Up the Project
As I mentioned a moment ago, our sample application will allow users to preview a document and open it in another application installed on the device. The latter is often very useful if you want to give your users more flexibility in terms of what they can do with the data stored in your application. A common example is opening a photo in a photo editing application, such as iPhoto.
Create a new project in Xcode by selecting the Single View Application template from the list of templates (figure 1). Name your application Documents, enter a company identifier, set iPhone for the device family, and check Use Automatic Reference Counting. The rest of the checkboxes can be left unchecked for this project (figure 2). Tell Xcode where you want to save the project and hit the Create button.
Figure 1
Figure 2
Step 2: Creating the User Interface
The user interface of our application will contain two buttons, one for previewing a PDF document and one for opening a PDF document in another application. Before we create the user interface, create an action for each button in the view controller's implementation file as shown below.
- (IBAction)previewDocument:(id)sender { }
- (IBAction)openDocument:(id)sender { }
Select MTViewController.xib and drag two UIButton
instances from the Object Library on the right in the view controller's view (figure 3). Select the File's Owner object on the left, open the Connections Inspector, and connect the actions that we created a moment ago with the buttons (figure 4). That is all we need to do in Interface Builder.
Figure 3
Figure 4
Step 3: Previewing a Document
The document that we will be working with is a PDF document. You can use any PDF document, but I have included a sample PDF document with the source files of this quick tip. It is Apple's iOS Programming Guide, which you can also find online. Drag the document into your project and make sure to check the checkbox labeled Copy items into destination group's folder (if needed) when you are prompted (figure 5). Also make sure that the document is added to the Documents target (figure 5).
Figure 5
When using the UIDocumentInteractionController
class, it is important to keep two things in mind, (1) you need to hold a reference to the document interaction controller and (2) the UIDocumentInteractionControllerDelegate
protocol needs to be implemented. Start by updating the view controller's header file as shown below to inform the compiler that the MTViewController
class conforms to the UIDocumentInteractionControllerDelegate
protocol.
#import <UIKit/UIKit.h> @interface MTViewController : UIViewController <UIDocumentInteractionControllerDelegate> @end
In the view controller's implementation file, add a private property of type UIDocumentInteractionController
and name it documentInteractionController
. This property will store the reference to the document interaction controller that we will be using.
Let's now take a look at the implementation of the previewDocument:
action. We start by obtaining the URL (NSURL
) of the document. Because the document is part of the application bundle, obtaining the document's URL is very easy thanks to a convenience method of the NSBundle
class (see below).
- (IBAction)previewDocument:(id)sender { NSURL *URL = [[NSBundle mainBundle] URLForResource:@"sample" withExtension:@"pdf"]; if (URL) { // Initialize Document Interaction Controller self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL]; // Configure Document Interaction Controller [self.documentInteractionController setDelegate:self]; // Preview PDF [self.documentInteractionController presentPreviewAnimated:YES]; } }
If a valid URL is returned to us, we initialize an instance of the UIDocumentInteractionController
class and pass the URL of the document. We store a reference to the document interaction controller in the documentInteractionController
property we created a minute ago. Our view controller will serve as the delegate of the document interaction controller. Presenting a preview of the PDF document is as easy as calling presentPreviewAnimated:
on the document interaction controller.
If you were to build and run the application now, you would notice that nothing happens when the button labeled Preview is tapped. There is one delegate method that we need to implement first. A few minutes ago, I told you that it is important to realize that the UIDocumentInteractionController
class is a subclass of NSObject
, not UIViewController
. Even though it will take care of displaying the document, we need to tell the document interaction controller which view controller to use for previewing the document. One of the delegate methods of the UIDocumentInteractionControllerDelegate
protocol asks the delegate for a view controller that it can use to preview the document. That delegate method is appropriately named documentInteractionControllerViewControllerForPreview:
. Because we want to display the preview in our main view controller, we can simple return self
as shown in the implementation below. What this means is that the document interaction controller will use our view controller to preview the PDF document. It will present a modal view in which it presents the document.
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller { return self; }
Of course, you can modify the implementation of documentInteractionControllerViewControllerForPreview:
to fit your needs. With the delegate method implemented, it is time to build and run our application for the first time and try it out (figure 6). Notice that you can even share the sample document via email, print it, or copy it to the clipboard. In addition, it is possible to open the document in any other application that supports the document's file type. Tap the button in the top right to see what I mean (figure 7).
Figure 6
Figure 7
Step 4: Opening a Document
In many situations, however, it is more appropriate to allow users to open a document in another application without first showing a preview of the document. To make this possible in our sample application, we need to implement the openDocument:
action. As in the previewDocument:
action, we obtain the URL of the sample PDF document in the application bundle and use it to initialize an instance of the UIDocumentInteractionController
class. After setting the delegate of the document interaction controller, we present a menu by calling presentOpenInMenuFromRect:inView:
on the document interaction controller. The CGRect
that we pass as the first argument is the frame of the button as you can see in the code snippet below.
- (IBAction)openDocument:(id)sender { UIButton *button = (UIButton *)sender; NSURL *URL = [[NSBundle mainBundle] URLForResource:@"sample" withExtension:@"pdf"]; if (URL) { // Initialize Document Interaction Controller self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL]; // Configure Document Interaction Controller [self.documentInteractionController setDelegate:self]; // Present Open In Menu [self.documentInteractionController presentOpenInMenuFromRect:[button frame] inView:self.view animated:YES]; } }
To test the openDocument:
action, it is important that you run the sample application on a physical device. The reason is simple. The operating system checks which applications on the device support the file type (UTI) that we want to open. If it cannot find any applications that support the corresponding file type, then it will not show an Open In menu and that is what will happen in the iOS Simulator.
To test this feature out, make sure that you have an application installed on your physical device that accepts PDF documents, such as Dropbox or Amazon's Kindle application.
Figure 8
Conclusion
As you can see, it is very easy to preview and open documents using the UIDocumentInteractionController
class. I recommend that you explore its class reference as well as the UIDocumentInteractionControllerDelegate
protocol. There are many more delegate methods that might come in handy especially when working with larger documents or complex workflows.
Comments