> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/ios/collaboration/server-i.md).

# Configuring server for realtime document collaboration on iOS

Learn how to add support for realtime collaboration in an iOS app with this comprehensive guide. Includes implementation details and sample code for using WebViewer Server and Firebase. The Apryse iOS

Support for realtime collaboration is included with the SDK, including demonstration implementations for using [WebViewer Server](/web/webviewer-server/wv-server-deployment.md) and [Firebase](https://firebase.google.com/products/realtime-database/) as a central server. You may consult these implementations in the Collaboration Sample as reference implementations (found in the .dmg download at `/Samples/Other/Collaboration/Collaboration/`, `TRNWebViewerServerService.m` and `TRNFirebaseCommunicationService.m`).

This guide will demonstrate how to add support for a **new** realtime collaboration server in an iOS app.

## Server requirements

In realtime collaboration, the role of the server is to:

* Store the annotations associated with a given document (these are provided by the SDK in an XML format)
* Send the annotations for a particular document to a user when requested
* Accept annotation creation/modification/deletion events from a user
* Broadcast annotation create/modification/deletion events to a user

If your server is capable of the above, it can serve as the back-end to Apryse's realtime collaboration.

This guide will explain how to configure an iOS app to interface with a server that fulfils the above requirements.

## Create a new collaboration service

To add support for a new server backend, you need to implement a single class, referred to here as the Collaboration Service. The purpose of the Collaboration Service object is to mediate between the server and the Apryse SDK. The Collaboration Service translates messages received from the server in its data format (for example json data) into to a format that the SDK understands (specifically a `PTCollaborationAnnotation`), and vice versa.

![](https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-88cf32e1a178cf2c9a9971eb9e60f08b48e10381%2F13c7f7f462cf8bfd9f90cc52f39c2dd27c5e5c85-960x384.svg?alt=media)

A Collaboration Service must implement the `PTCollaborationServerCommunication` protocol. The purpose of each API defined in the protocol will be described in the sections below.

### Send updates to the server

The Collaboration Service implements 3 methods defined in `PTCollaborationServerCommunication` in order to process changes made on the device:

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
-(void)localAnnotationAdded:(PTCollaborationAnnotation*)collaborationAnnotation;
-(void)localAnnotationModified:(PTCollaborationAnnotation*)collaborationAnnotation;
-(void)localAnnotationRemoved:(PTCollaborationAnnotation*)collaborationAnnotation;
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
func localAnnotationAdded(_ collaborationAnnotation: PTCollaborationAnnotation)
func localAnnotationModified(_ collaborationAnnotation: PTCollaborationAnnotation)
func localAnnotationRemoved(_ collaborationAnnotation: PTCollaborationAnnotation)
```

{% endcode %}
{% endtab %}
{% endtabs %}

Each of these methods is called by the `PTCollaborationManager` to communicate when a change has occurred on the device. They pass an object of type `PTCollaborationAnnotation`, which the collaboration service must then convert to a format appropriate for the server, and sends it to the server.

Here is a theoretical example:

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
-(void)localAnnotationModified:(PTCollaborationAnnotation*)collaborationAnnotation
{
    MYServerMessage* serverMessage = [[MYServerMessage alloc] init];
    
    serverMessage.action = @"annotationModified";
    serverMessage.xfdf = collaborationAnnotation.xfdf;
    serverMessage.annotationID = collaborationAnnotation.annotationID;
    serverMessage.userID = self.userID;
    
    [self.myServer sendMessage:serverMessage];
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
func localAnnotationModified(_ collaborationAnnotation: PTCollaborationAnnotation) {
    let serverMessage = MYServerMessage()

    serverMessage.action = "annotationModified"
    serverMessage.xfdf = collaborationAnnotation.xfdf
    serverMessage.annotationID = collaborationAnnotation.annotationID
    serverMessage.userID = userID

    myServer.send(serverMessage)
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Receive updates from the server

Likewise, the collaboration service is responsible for receiving updates from the server and communicating them to the Collaboration Manager, referenced in its `PTCollaborationManager` property.

This is done by calling the following Collaboration Manager methods:

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
-(void)remoteAnnotationAdded:(PTCollaborationAnnotation*)collaborationAnnotation;
-(void)remoteAnnotationModified:(PTCollaborationAnnotation*)collaborationAnnotation;
-(void)remoteAnnotationRemoved:(PTCollaborationAnnotation*)collaborationAnnotation;
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
func remoteAnnotationAdded(_ collaborationAnnotation: PTCollaborationAnnotation)
func remoteAnnotationModified(_ collaborationAnnotation: PTCollaborationAnnotation)
func remoteAnnotationRemoved(_ collaborationAnnotation: PTCollaborationAnnotation)
```

{% endcode %}
{% endtab %}
{% endtabs %}

As in the `localAnnotationAdded/Modified/Removed` methods described in the previous section, these methods take a `PTCollaborationAnnotation` parameter. It is the job of the collaboration service to receive a server message, translate it into a `PTCollaborationAnnotation` object, and call the appropriate method.

Here is a theoretical example:

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
-(void)didReceiveServerJson:(NSString*)serverJson
{
    MYServerMessage* serverMessage = [[MYServerMessage alloc] initFromJson:serverJson];

    PTCollaborationAnnotation* collabAnnot = [[PTCollaborationAnnotation alloc] init];

    collabAnnot.xfdf = serverMessage.xfdf;
    collabAnnot.userName = serverMessage.authorName;
    collabAnnot.annotationID = serverMessage.annotationID;
    collabAnnot.userID = serverMessage.userID;
    collabAnnot.parent = serverMessage.parent;
    collabAnnot.documentID = serverMessage.documentID;

    if( [serverMessage.action isEqualToString:@"annotationAdded"] )
    {
        [self.collaborationManager remoteAnnotationAdded:collabAnnot];
    }
    else if( [serverMessage.action isEqualToString:@"annotationModified"] )
    {
        [self.collaborationManager remoteAnnotationModified:collabAnnot];
    }
    else if( [serverMessage.action isEqualToString:@"annotationRemoved"] )
    {
        [self.collaborationManager remoteAnnotationRemoved:collabAnnot];
    }

}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
func didReceiveServerJson(_ serverJson: String) {
    let serverMessage = MYServerMessage(fromJson: serverJson)

    let collabAnnot = PTCollaborationAnnotation()

    collabAnnot.xfdf = serverMessage.xfdf
    collabAnnot.userName = serverMessage.authorName
    collabAnnot.annotationID = serverMessage.annotationID
    collabAnnot.userID = serverMessage.userID
    collabAnnot.parent = serverMessage.parent
    collabAnnot.documentID = serverMessage.documentID

    if (serverMessage.action == "annotationAdded") {
        collaborationManager.remoteAnnotationAdded(collabAnnot)
    } else if (serverMessage.action == "annotationModified") {
        collaborationManager.remoteAnnotationModified(collabAnnot)
    } else if (serverMessage.action == "annotationRemoved") {
        collaborationManager.remoteAnnotationRemoved(collabAnnot)
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Miscellaneous

1. The `PTCollaborationServerCommunication`, which a Collaboration Service must conform to, defines three other required APIs:

* Property `collaborationManager`. This should be assigned to the instance of the `PTCollaborationManager` that exists on a [`PTToolManager`](https://sdk.apryse.com/api/ios/Classes/PTToolManager.html). This is done automatically if using a `PTCollaborationDocumentViewController`, described below.
* Method `-(void)documentLoaded`. This method is intended to be called when a document is first loaded, and so when invoked the service should send all of the document's annotations to the `collaborationManager`'s `remoteAnnotationAdded:` method.
* Method `(NSString*)userID`, which returns the server's unique ID associated with the user. This can be used by the local viewer to restrict which annotations a user can edit.

1. The tools framework includes a class `PTCollaborationDocumentViewController`, which inherits from the standard `PTDocumentController`, that implements two useful functions for collaboration:

* Its constructor takes a `PTCollaborationServerCommunication` object, and automatically connects it with its `PTCollaborationManager`.
* It prevents the user from selecting (and thus editing) annotations that they did not create.

1. The `PTCollaborationServerCommunication` protocol does not have any opinion on where/how server login is performed.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/ios/collaboration/server-i.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
