PSPDFKit Instant and iOS Data Protection

PSPDFKit Instant works with iOS data protection.

If you set a default data protection level using an entitlement, Instant will use and adopt this for its content.

To set this up, add the entitlement to your app by navigating to the Signing & Capabilities section in Xcode, choose + Capability, and add Data Protection.

Adding the Swift package

This will add the following to the .entitlements file, and you can set the file protection to an appropriate level here:

<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>

Instant stores data in a path provided by the dataDirectory class property on InstantClient. However, setting the protection level on the directory to make the containing files inherit the protection level isn’t supported by Instant.

If you’re setting up the entitlement or upgrading the protection type on an existing installation in an app where Instant has already run, use a directory enumerator to change the protection level of already existing content. Decide on an appropriate way to handle errors rather than just logging them:

guard let directoryEnumerator = FileManager.default.enumerator(at: InstantClient.dataDirectory, includingPropertiesForKeys: [], options: [], errorHandler: { url, error -> Bool in
    print(error)
    return true
}) else {
    print("Could not create enumerator for Instant data directory.")
    return false
}

// `NSEnumerator` is not generic in Swift so we have to deal with `Any`.
while let file = directoryEnumerator.nextObject() as? NSURL {
    try file.setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey)
}
NSDirectoryEnumerator<NSURL *> *enumerator = [NSFileManager.defaultManager enumeratorAtURL:PSPDFInstantClient.dataDirectory includingPropertiesForKeys:@[] options:0 errorHandler:^BOOL(NSURL *url, NSError *error) {
    NSLog(@"%@", error);
    return YES;
}];

if (enumerator == nil) {
    NSLog(@"Could not create enumerator for Instant data directory.");
}

for (NSURL *url in enumerator) {
    NSError *error;

    if (![url setResourceValue:NSURLFileProtectionComplete forKey:NSURLFileProtectionKey error:&error]) {
        NSLog(@"%@", error);
    }
}

ℹ️ Note: There’s a file called metadata-shm in dataDirectory, and it’s needed for the server metadata database Instant manages. This file always uses the default file protection level .completeUntilFirstUserAuthentication to function. However, it doesn’t contain any persistent content, and it’s only used to provide information for multiple processes using the database. For more information on SQLite helper files, see the official documentation.