Creating PDF Annotation Layers on iOS
An Instant layer is a container for annotations on a specific PDF document. For everyone with write access to this container, the layer provides an editing context for the annotations it contains. People who only have read access to a layer may still download and view the document with all the annotations in the container. However, they won’t be able to make any changes to those annotations.
Instant layers are particularly useful for implementing review workflows where several parties are invited to provide feedback on a document independent of one another. One example would be student-teacher workflows, where all students independently annotate the same PDF document, while the teacher can annotate each student’s private layer, which only the student can see.
Because all layers with the same document identifier can share the same PDF file, adding a layer is cheap in terms of storage and bandwidth — on the clients as well as on the server.
Terminology
In Instant for iOS, we represent a layer using the InstantDocumentDescriptor
protocol. Compared to earlier releases, the responsibilities and general semantics of that API remain untouched. However, the terms “document,” “document descriptor,” and “PDF file” are no longer used interchangeably. Instead:
-
A PDF file corresponds to the file for a certain document identifier.
-
There can be multiple layers for any document identifier, and each layer corresponds to exactly one document descriptor.
-
For display and editing purposes, you can obtain one or more
Document
instances (i.e. documents) from a document descriptor.
ℹ️ Note: To further clarify the distinction between document and document descriptor, the old delegate methods in
InstantClientDelegate
have been deprecated. Their replacements now all explicitly refer to a document descriptor in their names.
Instant Layers in Practice
When you upload a new PDF file to Document Engine, the server assigns a document identifier to that file. All annotations in that file are extracted into an immutable base layer. You can create custom layers for a document identifier by issuing JSON Web Tokens (JWTs) that contain the desired name for the layer in the (optional) layer
claim, where each layer is uniquely identified by the combination of document identifier and layer name. A new layer mirrors the content of the base layer until the first change is made to its content, which means layers don’t have to be created manually, rather they’re created on demand once the first changes are synced.
If the layer
claim is omitted in the JWT, the “default layer” for that document identifier is used. So if you’re already using Instant, all your annotations will be in this default layer, and you can continue using the default layer without having to change anything on your server or in your client code.
For more technical information about layers, take a look at our Instant Layers guide for Document Engine. To learn more about some of the design considerations and our vision for Instant layers, please read the Instant layers blog post.
Try Layers for Yourself
To see layers in action without having to touch your server setup, you can use our example applications:
-
Follow the steps in our Example Projects guide for Document Engine, and log in to the example web app in your favorite browser as the user
test
. A fresh server will be prepopulated with a sample PDF called Document#1, and you can always upload additional PDFs using the Upload PDF button. -
Open a document by clicking on its thumbnail, and create a new text annotation with the content
default layer
on the first page — this will make it easy later on for you to see which layer you’re dealing with. -
Type
test
in the Create New Layer field (in the right pane) and click the Create Layer button. -
Create a new text annotation with the content
layer 'test'
on the first page — you can now switch back and forth between the default layer and thetest
layer by clicking on the entries of the Available Layers list in the right pane. If you want, you can create additional layers by typing their names in the text field and adding an annotation to the new layer.
Follow the steps in our Get Started guide for Instant to build and run the iOS example application. This is what allows you to see your existing layers on iOS. When running, the app will display a table view with one section for each PDF file you’ve uploaded to the example server containing one cell for each layer. After tapping one of the cells, the appropriate PDF file and annotation data will be downloaded as necessary. If you tap another cell in the same section, you’ll notice how much more quickly the second layer for that file is opened; because the file is shared, only the annotation data needed to be fetched.
Using Layers in Your Own App
To use non-default layers, your JWTs need to include the layer
claim. To obtain the document descriptor for any layer, call the documentDescriptor(forJWT:)
method on your InstantClient
, passing in the JWT.
ℹ️ Note: Because you need a JWT to obtain a document descriptor for a custom layer that hasn’t yet been loaded, we suggest designing the API endpoint that lists all the layers a user has access to in such a way that the response includes the JWT for each layer. This also greatly reduces the number of server roundtrips needed to, for example, update all downloaded layers.
Related Improvements
To make it quicker and easier to identify integration errors, updating the JWT for a document identifier no longer requires a server roundtrip to reject incompatible tokens. And if your JWT contains the user_id
claim, we now also reject those mismatches immediately. This is especially useful in combination with the new localDocumentDescriptors()
API.
For the complete list of changes, head over to our changelog.