Customizing Digital Signatures in iOS

PSPDFKit offers various options for customizing the digital signing experience, primarily via DigitalSignatureCoordinator subclassing hooks.

File Path for Digitally Signed Documents

A document that is digitally signed will be copied, signed, and saved to a new path to keep the (unsigned) original document intact. You can customize the path where the digitally signed document should be saved by subclassing DigitalSignatureCoordinator and overriding pathForDigitallySignedDocument(fromOriginalDocument:suggestedFileName:) to return a custom path. The suggested file name parameter is based on the title of the original document, if available, or the file name as a fallback. It can be used as the last path component in the path where the digitally signed document should be stored. The returned path will be sanitized, and we will append the .pdf path extension.

Presentation for Digitally Signed Documents

You can also customize how the signed document should be presented. By default, this is done by pushing a new PDFViewController instance on the navigation controller with the digitally signed document shown. This can be customized by overriding presentSignedDocument(_:showingPageIndex:with:) in your DigitalSignatureCoordinator subclass. By overriding this method, you are responsible for presenting/pushing the document that should be part of your digital signing experience. The pageIndex parameter is the page index of the signature form field of the document, which you have the option of scrolling to.

Biometric Data

By default, all available properties on PDFSignatureBiometricProperties are populated and stored. These properties can be customized to restrict storing specific properties via PDFConfiguration.signatureBiometricPropertiesOptions. When signing a document, only the specified values are stored in the digital signature.

For example, to only store the touch radius and the input method biometric properties of the ink signature, you can use the following code:

let controller = PDFViewController(document: document) {
    $0.signatureBiometricPropertiesOptions = [.touchRadius, .inputMethod]
}
PSPDFViewController *controller = [[PSPDFViewController alloc] initWithDocument:document configuration:[PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    builder.signatureBiometricPropertiesOptions = PSPDFSignatureBiometricPropertiesOptionTouchRadius | PSPDFSignatureBiometricPropertiesOptionInputMethod;
}]];

You can customize the properties that are stored by overriding SignatureContainer(annotation:signer:biometricProperties:) and modifying the biometricProperties object to fit your needs.

Signature Appearances

During the signing process, you can customize how the final signature will be shown in the document.

PDFSignatureAppearance has some Boolean properties to decide whether the signer’s name, date of signing, signature location, or signature reason should be shown after the document is signed.

The appearanceMode property enables further configuration of the visual appearance, with three supported modes: .signatureAndDescription, .signatureOnly, and .descriptionOnly. If your signature field has some appearance you want to keep after it’s signed (for example, a border or watermark logo), set the reuseExistingAppearance property.

You can provide your own artwork (for example, a handwritten signature) that will be displayed on the left part of a signature field when its appearance mode is .signatureAndDescription. Set the signatureGraphic property to type Annotation.AppearanceStream to accomplish this. You can create an Annotation.AppearanceStream with either a JPEG image or a PDF document. The signature watermark that will be drawn in the center of the signature can also be configured. Set the signatureWatermark property to accomplish this. If you don’t configure this property, the PSPDFKit logo will be shown. If you don’t want to show a signature watermark at all, set the showWatermark property to false.

If you are signing a document programmatically, you can pass the PDFSignatureAppearance class by configuring the dataSource property of the PDFSigner instance, like this:

// A custom document signer data source that will provide the custom signature appearance.
class MyCustomDataSource: NSObject, PDFDocumentSignerDataSource {
    func documentSigner(_ signer: PDFSigner, signatureAppearance formFieldFqn: String) -> PDFSignatureAppearance {
         let image = ...
         let signatureAppearance = PDFSignatureAppearance { builder in
             builder.appearanceMode = .signatureAndDescription
             builder.reuseExistingAppearance = true
             builder.signatureGraphic = Annotation.AppearanceStream(image: image!)
         }
         return signatureAppearance
    }
}

// Set the custom signer's data source.
let customDataSource = MyCustomDataSource()
signer.dataSource = customDataSource

// Sign the document.
var signedDocument: Document?
signer.sign(signatureFormElement, usingPassword: "test", writeTo: path) {(_ success: Bool, _ document: Document, _ err: Error?) -> Void in
    signedDocument = document
}
// A custom document signer data source that will provide the custom signature appearance.
@interface MyCustomDataSource: NSObject<PSPDFDocumentSignerDataSource>

@end

@implementation MyCustomDataSource

- (PSPDFSignatureAppearance *)documentSigner:(PSPDFSigner *)signer signatureAppearance:(NSString *)formFieldFqn {
    PSPDFSignatureAppearance *signatureAppearance = [PSPDFSignatureAppearance configurationWithBuilder:^(PSPDFSignatureAppearanceBuilder *builder) {
       builder.appearanceMode = PSPDFSignatureAppearanceModeSignatureAndDescription;
       builder.reuseExistingAppearance = YES;
       builder.signatureGraphic = [PSPDFAnnotationAppearanceStream appearanceStreamWithImage:image];
    }];
    return signatureAppearance;
}

@end

// Set the custom signer's data source.
let customDataSource = [[MyCustomDataSource alloc] init];
signer.dataSource = customDataSource;

// Sign the document.
__block PSPDFDocument *signedDocument;
[signer signFormElement:signatureFormElement usingPassword:@"test" writeTo:path completion:^(BOOL success, PSPDFDocument *document, NSError *err) {
    signedDocument = document;
}];

When providing an ink signature, the default signature appearance looks like the following image.