An Overview of the iOS Document Browser View Controller

From Techotopia
Revision as of 16:12, 7 March 2018 by Neil (Talk | contribs)

Jump to: navigation, search

The previous chapters have introduced ways to integrate file handling into an iOS application in terms of local and iCloud-based storage. In these chapters, the assumption has been made that all of the user interface aspects of the file handling and file system navigation will be provided in some way by the app itself. An alternative to integrating file handling in this way is to make use of the iOS document browser view controller.

This chapter provides a basic overview of this class in preparation for a tutorial in the next chapter.


Contents


An Overview of the Document Browser View Controller

The document browser view controller is implemented using the UIDocumentBrowserViewController class and provides a visual environment in which users can navigate file systems and select and manage files from within an iOS app. The document browser provides the user with access to both the local device file system and iCloud storage in addition to third-party providers such as Google Drive.

To see the browser in action, take some time to explore the new Files app included as standard with iOS 11. Figure 43-1, for example, shows the Files app being used to browse a user's iCloud Drive files and folders:


[[File:]]

Figure 43-1

When integrated into an app, the document browser provides the same functionality as the Files app in addition to the ability to create new files.

As with the Files app, when the browser is integrated into an app, performing a long press over the app's launcher icon will display a popup containing the most recently accessed files:


[[File:]]

Figure 43-2


The Anatomy of a Document Based App

The key elements that interact to provide the document browser functionality within an iOS app are a UIDocumentBrowserViewController instance, access to one or more file providers (for example the local file system, iCloud Drive, Google Drive etc.) and at least one additional view controller in which to present any selected file content to the user. When working with files in conjunction with the document browser, the use of the UIDocument class for the lower level file handling tasks is still recommended, so a subclass of UIDocument will also typically be included (the UIDocument class was covered in the chapter entitled Managing Files using the iOS UIDocument Class).

Adding document browser support to an app is a multistep process that begins with the creation of a UIDocumentBrowserViewController instance. When doing this it is essential that the browser is the root view controller of the app. By far the easiest way to start the development process is to use the Xcode Document Based App template when creating a new project as shown in Figure 43-3:

[[File:]]

Figure 43 3

A project created using the Document Based App template will contain the following files by default:

  • DocumentBrowserViewController.swift - The root view controller for the app derived from the UIDocumentBrowserViewController class. This file contains stub delegate methods ready to be completed to implement app specific document browser behavior.
  • Document.swift - A subclass of the UIDocument class containing stub methods.
  • DocumentViewController.swift - A template view controller intended to present the selected files to the user. This template implementation simply displays the file name and a "Done" button to return to the document browser.

Document Browser Project Settings

A number of Info.plist settings need to be configured to enable document browser support within an app project. The first is the Supports Document Browser (UISupportsDocumentBrowser) key which must to set to YES. Next, the app needs to declare the document types it is capable of handling and the action the app is able to perform on those types (i.e. viewing only or viewing and editing). These settings dictate the types of file that will be selectable within the document browser.

Each supported type must, at a minimum, include the following key-value information:

  • CFBundleTypeName - A string value that uniquely identifies the type within the context of the app.
  • CFBundleTypeRole - A string value indicating the action that the app will perform on the file (i.e. Editor or Viewer)
  • LSHandlerRank - A string value that declares to the system how the app relates to the file type. If the app uses its own custom file type, this should be set to Owner. If the app is to be opened as the default app for files of this type, the value should be set to Default. If, on the other hand, the app can handle files of this type but is not intended to be default handler a value of Alternate should be used. Finally, None, should be used if the app is not to be associated with the file type.
  • LSItemContentTypes - An array of Universal Type Identifiers (UTI) indicating the file types supported by the app. These can be custom file types unique to the app or, more commonly, standard identifiers provided by Apple such as public.image, public.text, public.plain-text and public.rtf.

As will be outlined in the next chapter, the easiest way to configure these keys is within the Info panel of the Xcode project target screen.

The Document Browser Delegate Methods

When the user selects a file from within the document browser of an app, a number of delegate methods implemented within the document browser view controller will be called. These methods can be summarized as follows:

didRequestDocumentCreationWithHandler

This method is called when the user requests the creation of a new file from within the document browser. It is the responsibility of this method to provide a template file and to pass the URL for that file to the importHandler method. The template file can either be a file that is already bundled with the app, or a file that is created on demand within the delegate method. This method also provides the app with the opportunity to display a selection screen to choose the template type if the app supports more than one file type or template option.

The importHandler method interacts with the appropriate file provider to create the file in the designated location. If, for example, the user was browsing an iCloud Drive location when making the file creation request, the importHandler method will work with the iCloud Drive file provider to create the new file in that location.

In addition to providing the URL of the template file, the importHandler method also needs to be passed a value indicating whether the template file should be moved (.move) or copied (.copy) to the location on the file provider. If the delegate method created a temporary file to act as the template a move operation is more likely. For a template file bundled with the app it will make more sense to copy the file since it will need to be available for future creation operations.

If the user cancels the creation process the importHandler method must be called with a nil file URL and a none (.none) value. The following code shows an example method implementation which uses a bundled file named template.txt as the template:

func documentBrowser(_ controller: UIDocumentBrowserViewController, 
  didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, 
   UIDocumentBrowserViewController.ImportMode) -> Void) {
    
    let newDocumentURL: URL? = Bundle.main.url(forResource: "template", 
					withExtension: "txt")
    
    if newDocumentURL != nil {
        importHandler(newDocumentURL, .copy)
    } else {
        importHandler(nil, .none)
    }
}

didImportDocumentAt

This method is called when a new document has been successfully created by the file provider (in other words, the importHandler method call was successful). When called, this method is passed both the source URL of the local template file and the destination URL of the file now residing on the file provider. This method will typically display the view controller that is responsible for presenting the file content to the user:

func documentBrowser(_ controller: UIDocumentBrowserViewController, 
  didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {
        
    presentDocument(at: destinationURL)
}

The presentDocument method called in the above example is a useful utility method included as part of the Document Based App project template for the document browser view controller class.

didPickDocumentURLs

This method is called when the user requests the opening of one or more existing files within the document browser. The URLs for the selected files are passed to the method in the form of an array and it is the responsibility of this method to pass these URLs to, and present, the document view controller. The default implementation for this method simply passes the first URL in the array to the presentDocument method:

func documentBrowser(_ controller: UIDocumentBrowserViewController, 
  didPickDocumentURLs documentURLs: [URL]) {
        guard let sourceURL = documentURLs.first else { return }
        
    presentDocument(at: sourceURL)
}

failedToImportDocumentAt

Called when the document import request fails, this method should notify the user of the failure, details of which can be extracted from the error object:

func documentBrowser(_ controller: UIDocumentBrowserViewController, 
  failedToImportDocumentAt documentURL: URL, error: Error?) {

        notifyUser(error?.localizedDescription
}

Customizing the Document Browser

A number of properties are available for customizing the document browser. The allowsPickingMultipleItems property controls whether the user is able to select multiple files: allowsPickingMultipleItems = false

The allowsDocumentCreation property defines whether the user can create new files (essentially defining whether or not the create file buttons appear in the browser):

allowsDocumentCreation = true

The visual appearance of the browser can be changed by setting the browserUserInterfaceStyle property to dark, light or white:

browserUserInterfaceStyle = .dark

Finally the tint color used by the browser (primarily the color used for text foreground and icons) can be changed via the tintColor property:

view.tintColor = .yellow

Adding Browser Actions

Performing a long press on a file within the document browser displays the edit menu (Figure 43-4) containing a range of built-in options including copy, delete, rename and share.


[[File:]]

Figure 43-4

These options also appear in the navigation bar at the bottom of the screen when the user enters select mode by tapping the Select button in the top right hand corner of the browser window.

Custom actions may be added to these menus by assigning an array of UIDocumentBrowserActions objects to the customActions property of the document browser view controller instance. A UIDocumentBrowserActions object consists of a unique identifier, a string to appear on the button, an array of locations where the action is to be available (options are menu and navigation bar) and a completion handler to be called when the action is selected. The completion handler is provided with an array of URLs representing the files selected at the time the action was triggered.

The action object also needs to be configured with the file types for which it is to appear and a property setting indicating whether the action can work with multiple file selections. The following example creates and assigns a browser action for text and plain text file types that works only with single file selections and displays "Convert" as the action title:

let action = UIDocumentBrowserAction(identifier: 
   "com.ebookfrenzy.docdemo.convert", localizedTitle: "Convert",
        availability: [.menu, .navigationBar], handler: { urls in

	// Code to be executed when action is selected                                                

})

action.supportedContentTypes = ["public.text", "public.plain-text"]
action.supportsMultipleItems = false
customActions = [action]

Summary

The UIDocumentBrowserViewController class provides an easy way to build document browsing into iOS apps. Designed to integrate with the local filesystem, iCloud Drive and other third-party file providers such as Google Drive and DropBox, the document browser can be integrated with minimal programming effort. Integration primarily consists of adding a UIDocumentBrowserViewController as the root view controller, setting some Info.plist properties and writing some delegate methods. Much of the preparatory work is performed automatically when a new Xcode project is created using the Document Based App template.