Document Sharing

PSPDFKit has the ability to share documents with other applications and services installed on a device, and it offers a set of APIs to customize the options that are available for the user when doing so.

You can share any document by tapping the Share button in the navigation bar and choosing what format you’d like to share the document in (where applicable), the page range you’d like to share, and how you’d like to manage the annotations in the document (if any). Once these are specified, you can tap on the Share button at the bottom of the screen.

Sharing Destinations

PSPDFKit 8 for iOS introduces the concept of sharing destinations to use with the revamped PSPDFDocumentSharingViewController. You can set up sharing destinations — like Mail, Messages, or similar — that define where a document will be sent after the user presses the Share button in the UI.

There are six destinations built into PSPDFKit that you can use out of the box:

Destination Behavior
PSPDFDocumentSharingDestinationActivity Shares to a standard UIActivityViewController instance. This is the default destination.
PSPDFDocumentSharingDestinationExport Shares to UIDocumentPickerViewController on iOS 11 and above and to UIDocumentMenuViewController on iOS 10.
PSPDFDocumentSharingDestinationMessage Shares to Messages.app with the resulting files as attachments. Requires the ability to send attachments.
PSPDFDocumentSharingDestinationEmail Shares to Mail.app with the resulting files as attachments. Requires Mail.app to be installed and configured correctly on the device.
PSPDFDocumentSharingDestinationOtherApplication Shares to a standard UIDocumentInteractionController.
PSPDFDocumentSharingDestinationPrint Starts a printing operation via UIPrintInteractionController.

To choose a destination to share to, create a PSPDFDocumentSharingConfiguration instance and set the destination property on its builder to your preferred destination. Then set that configuration on your PSPDFDocumentSharingViewController’s sharingConfigurations property.

Note that a single sharing view controller instance can hold multiple destinations at the same time, and the destinations that are available will be displayed in a segmented control on the top of the view controller:

Copy
1
2
3
4
5
6
7
let configurations = [
    PSPDFDocumentSharingConfiguration.defaultConfiguration(forDestination: .activity),
    PSPDFDocumentSharingConfiguration.defaultConfiguration(forDestination: .print)
]

let sharingController = PSPDFDocumentSharingViewController(documents: [document])
sharingController.sharingConfigurations = configurations
Copy
1
2
3
4
5
6
7
NSArray<PSPDFDocumentSharingConfiguration *> *configurations = @[
    [PSPDFDocumentSharingConfiguration defaultConfigurationForDestination:PSPDFDocumentSharingDestinationActivity],
    [PSPDFDocumentSharingConfiguration defaultConfigurationForDestination:PSPDFDocumentSharingDestinationPrint]
];

PSPDFDocumentSharingViewController *sharingController = [[PSPDFDocumentSharingViewController alloc] initWithDocuments:@[document]];
sharingController.sharingConfigurations = configurations;

Only one configuration per destination is allowed.

Sharing Configurations

A sharing configuration (see PSPDFDocumentSharingConfiguration’s API documentation) object defines the set of options that are available for sharing documents. These include file formats, page selection abilities, annotation processing preferences, the target destination, and more:

Copy
1
2
3
4
5
6
7
let customConfiguration = PSPDFDocumentSharingConfiguration {
    $0.destination = .export
	$0.fileFormatOptions = [.PDF]
	$0.annotationOptions.remove(.embed)
}

sharingController.sharingConfigurations = [customConfiguration]
Copy
1
2
3
4
5
6
7
PSPDFDocumentSharingConfiguration *customConfiguration = [PSPDFDocumentSharingConfiguration configurationWithBuilder:^(PSPDFDocumentSharingConfigurationBuilder *builder) {
	builder.destination = PSPDFDocumentSharingDestinationExport;
	builder.fileFormatOptions = PSPDFDocumentSharingFileFormatOptionPDF;
	builder.annotationOptions &= ~PSPDFDocumentSharingAnnotationOptionEmbed;
}];

sharingController.sharingConfigurations = @[customConfiguration];

The example above defines a configuration object that will allow a user to export the documents in PDF format. The fact that the Embed annotation option is being removed from the annotationOptions property means the user won’t be able share a PDF with editable annotations, and the UI will only present the remaining annotation options (Flatten, Remove, Summary).

In this example, the default selected option for how to handle annotations (PSPDFDocumentSharingAnnotationOptions) is inferred in order of relevance, which is defined as follows:

  1. Embed
  2. Flatten
  3. Summary
  4. Remove

If one option is not available, the next one becomes the default one selected when the view controller is presented.

The file format options behave differently, as the default selected option will be determined by the context of the documents being shared.

  1. If the document is an image (PSPDFImageDocument) and PSPDFDocumentSharingFileFormatOptionImage is available, PSPDFDocumentSharingFileFormatOptionImage will be the option selected by default.
  2. If the document has an original file set and PSPDFDocumentSharingFileFormatOptionOriginal is available, PSPDFDocumentSharingFileFormatOptionOriginal will be the option selected by default.
  3. For every other condition, PSPDFDocumentSharingFileFormatOptionPDF will be the option selected by default.

The default selected options can be updated via the selectedAnnotationOption, selectedFileFormatOption, and selectedPageSelectionOption properties on PSPDFDocumentSharingViewController.

By default, a PSPDFDocumentSharingViewController instance will have only one configuration set on its sharingConfigurations property. This default configuration has the destination PSPDFDocumentSharingDestinationActivity and all configuration options enabled.

Preconfigured PSPDFDocumentSharingConfiguration instances can be obtained by calling +[PSPDFDocumentSharingConfiguration defaultConfigurationForDestination:].

Setting a default set of Sharing Configurations can be done directly on the PSPDFConfiguration object you use to instantiate your PSPDFViewController:

Copy
1
2
3
4
5
let configuration = PSPDFConfiguration {
    $0.sharingConfigurations = customSharingConfigurations
}

let controller = PSPDFViewController(document: document, configuration: configuration)
Copy
1
2
3
4
5
PSPDFConfiguration *configuration = [PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    builder.sharingConfigurations = customSharingConfigurations;
}];

PSPDFViewController *controller = [[PSPDFViewController alloc] initWithDocument:document configuration:configuration];

Presenting the UI

Once the sharing view controller instance has been updated with the desired configuration, call -presentFromViewController:sender: to show the UI:

1
2
sharingController.delegate = self
sharingController.present(from: self, sender: sender)
1
2
sharingController.delegate = self;
[sharingController presentFromViewController:self sender:sender];

When -presentFromViewController:sender: is called, the sharing view controller will review its configurations and decide whether or not it’s appropriate to show the sharing option picking UI or not. If it is not, the files will be generated immediately and the final destination UI will be shown instead of the standard configuration UI.

The following example illustrates this:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
@objc func customPrintButtonTapped(sender: Any) {
    let directPrintingConfiguration = PSPDFDocumentSharingConfiguration {
    	$0.destination = .print
    	$0.fileFormatOptions = [.PDF]
    	$0.annotationOptions = [.remove]
    	$0.pageSelectionOptions = [.all]
    }

    let sharingController = PSPDFDocumentSharingViewController(documents: [document])
    sharingController.sharingConfigurations = [directPrintingConfiguration]
    sharingController.present(from: self, sender: sender)
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
- (void)printButtonTapped:(id)sender {
    PSPDFDocumentSharingConfiguration *directPrintingConfiguration = [PSPDFDocumentSharingConfiguration configurationWithBuilder:^(PSPDFDocumentSharingConfigurationBuilder * builder) {
        builder.destination = PSPDFDocumentSharingDestinationPrint;
        builder.fileFormatOptions = PSPDFDocumentSharingFileFormatOptionPDF;
        builder.annotationOptions = PSPDFDocumentSharingAnnotationOptionRemove;
        builder.pageSelectionOptions = PSPDFDocumentSharingPagesOptionAll;
    }];

    PSPDFDocumentSharingViewController *sharingController = [[PSPDFDocumentSharingViewController alloc] initWithDocuments:@[self.document]];
    sharingController.sharingConfigurations = @[directPrintingConfiguration];
    [sharingController presentFromViewController:self sender:sender];
}

The code sample above creates a Sharing Configuration that has single options for all categories (PDF, Remove Annotations, All Pages), and has the Print destination set. Since there are no options to choose from in this scenario, the option picking UI will be skipped entirely, and the printing interface will be shown instead.

Furthermore, you can call -commitWithCurrentConfiguration on your PSPDFDocumentSharingViewController instance to take whatever is currently selected on the current configuration, generate the appropriate files, and send them to the appropriate destination in a single step.

Hooking Into the Sharing Flow

The PSPDFDocumentSharingViewControllerDelegate protocol offers a comprehensive set of callbacks that let you hook into the sharing process.

For instance, here’s how to change the names for the files being shared:

Copy
1
2
3
4
func documentSharingViewController(_ shareController: PSPDFDocumentSharingViewController, willShare files: [PSPDFFile]) -> [PSPDFFile] {
    let newFiles = files.map { PSPDFFile(name: "My Cool Name", url: $0.fileURL, data: $0.fileData) }
    return newFiles
}
Copy
1
2
3
4
5
6
7
8
- (NSArray<PSPDFFile *> *)documentSharingViewController:(PSPDFDocumentSharingViewController *)shareController willShareFiles:(NSArray<PSPDFFile *> *)files {
    NSMutableArray *newFiles = [NSMutableArray arrayWithCapacity:files.count];
    [files enumerateObjectsUsingBlock:^(PSPDFFile * file, NSUInteger idx, BOOL * _Nonnull stop) {
        PSPDFFile *newFile = [[PSPDFFile alloc] initWithName:@"My Cool Name" URL:file.fileURL data:file.fileData];
        [newFiles addObject:newFile];
    }];
    return newFiles;
}

And here’s how to be notified about how far along the file processing is:

Copy
1
2
3
func documentSharingViewController(_ shareController: PSPDFDocumentSharingViewController, preparationProgress progress: CGFloat) {
    updateProgressBar(progress: progress)
}
Copy
1
2
3
- (void)documentSharingViewController:(PSPDFDocumentSharingViewController *)shareController preparationProgress:(CGFloat)progress {
    [self updateProgressBar:progress];
}

You can even react to the user canceling the sharing of the documents based on how far along in the process they were:

Copy
1
2
3
4
5
6
7
8
9
func documentSharingViewController(_ shareController: PSPDFDocumentSharingViewController, didCancelSharingAt sharingStep: PSPDFDocumentSharingStep, with configuration: PSPDFDocumentSharingConfiguration) {
    switch sharingStep {
    case .configuration:
        // Files hadn't been generated yet.

    case .destination:
        // User canceled after files were generated.
    }
}
Copy
1
2
3
4
5
6
7
8
9
10
11
- (void)documentSharingViewController:(PSPDFDocumentSharingViewController *)shareController didCancelSharingAtStep:(PSPDFDocumentSharingStep)sharingStep withConfiguration:(PSPDFDocumentSharingConfiguration *)configuration {
    switch (sharingStep) {
        case PSPDFDocumentSharingStepConfiguration:
            // Files hadn't been generated yet.
            break;

        case PSPDFDocumentSharingStepDestination:
            // User canceled after files were generated.
            break;
    }
}

There’s much more that can be done via the PSPDFDocumentSharingViewControllerDelegate protocol, so make sure you take a dive into its documentation.

Modifying the Email Subject

When sharing to the PSPDFDocumentSharingDestinationEmail destination, the default subject on the mail compose view will be the title of the document that’s being shared.

If you wish to have the email subject be something else, you can update the sharing document’s Title property. Be advised that modifying the -[PSPDFDocument title] property directly does not save the new value back to the actual PDF file, and this will only affect the current instance of the document you’re working with.

To update the document’s title and make sure the changes are saved into the actual document (not just the in-memory instance), you can use the PSPDFDocumentPDFMetadata class. You can learn more about updating a PDF’s metadata in our Customizing Document Metadata guide.