# iOS client SDK

The Sending.Network iOS SDK provides a messaging framework that enables you to integrate chatroom and notification services within your mobile applications. This quickstart will show you how to set up the SDK and make API calls like user registration, room creation, etc. Let's explore how we would make a simple client that can send and receive messages, create a chat room, get member lists, etc.

## Prerequisites

| Components | Requirements                                                                                                                              |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| OS         | iOS 14 or above                                                                                                                           |
| Software   | <ul><li>Xcode 13.0 or above</li><li><a href="https://github.com/Sending-Network/sendingnetwork-ios">Sending.Network iOS SDK</a></li></ul> |

## Installation

### **CocoaPods based Installation**

You can connect to SDN network by running a local P2P service or connecting to an existing Edge Node.

{% tabs %}
{% tab title="Conenct an Edge Node" %}
To build the application that connects to an existing Edge Node, add the following line to the _podfile_.

```ruby
pod SendingnetworkSDK/Lite
```
{% endtab %}

{% tab title="Create local P2P service" %}
To build the application that runs a local P2P service, add the following line to the _podfile_.

```ruby
pod SendingnetworkSDK
```
{% endtab %}
{% endtabs %}

### **Include the header**

```swift
import SendingnetworkSDK
```

### Start the local P2P service

If you connect to an existing edge node in the previous step, you can safely skip this step. \
\
To create a local P2P service:

```swift
RadixService.shared.start()
```

### **Initialize the client**

{% hint style="info" %}
If you choose to connect to an existing Edge Node in the previous step, please contact developer@sending.network for a test node URL and assign it to`credentials.homeserver`.
{% endhint %}

```swift
var client:MXRestClient?
let credentials = MXCredentials()
credentials.node = "http://localhost:65432"
self.client = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil)
```

#### Login in to user DID

```swift
func DIDLogin() {
  client?.getDIDList(walletAddress, success: { [weak self]  response in
     pre_loginDID(did: response?.array[0])
    }, failure: { error in
  })
}

func pre_loginDID(did: String) {
   client?.postPreLoginDID(did, success: {[weak self] response in
       let token = self.signinMessage(message: response.message, did: response.did)
       self.loginWithDID(identifier: ["did":did,"token":token], updateTime: response.updated)
     }, failure: { error in
    })
}

func loginWithDID(identifier: [String: String], updateTime: String) {
    client?.postLoginDID(did, withParameter: ["type":" m.login.did.identity","updated":updateTime,"identifier":identifier], success: { response in
        print("\(response.accessToken),\(response.userId),\(response.homeServer),\(response.deviceId),\(response.guideState)")
    }, failure: { error in
    })
}
```

Keeping your access token safe is essential, as it allows complete access to your account.

#### Log in with your access token

Instantiate a new client object and use the access token to log in:

```swift
// Login with the access token
let credentials = MXCredentials(homeServer: "http://localhost:65432",
                                userId: "YOUR_USER_ID",
                                accessToken: "YOUR_ACCESS_TOKEN")
// Create a client
let client = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil)

// Create a session to interact with the server and keep it throughout the app's lifetime
// or until the user logs out:
let session = MXSession(sendingNetworkRestClient: client)
```

#### Sync and listen

Next, we start the client which sets up the connection to the server and performs the first sync, then listen for the response to get the latest state from the server:

```swift
// Create a session to interact with the server and keep it throughout the app's lifetime
// or until the user logs out:
let session = MXSession(sendingnetworkRestClient: client)
session.start { response in
    guard response.isSuccess else {
        print("sync envnt failed")
        return
    }
    session.listenToEvents(){ event, direction, customObject in
        switch direction {
            case .forwards:
                 // Live/New events come here
                 if event.eventId != nil{
                    switch event.wireType{
                    // Got a message from other user.
                    case kMXEventTypeStringRoomMessage:
                        let msg = event.content["body"] as! String
                        print("got message: ", msg, " from: ", event.sender!, "at time: ", event.ageLocalTs)
                        // Send a receipt, then the message won't send again.
                        self.client?.sendReadReceipt(toRoom: event.roomId, forEvent: event.eventId){ response in }
                        break;

                    // Got a room event.
                    case kMXEventTypeStringRoomMember:
                        let ms = event.content["membership"] as! String
                        if  ms == "invite"{
                            // Invited by a user.
                            print("invited to room: \(event.roomId!) by user: \(event.sender!)")
                            self.join_room(room_id: event.roomId!)
                        }else if ms == "join"{
                            print("join the room: ", event.roomId)
                        }
                        break;
                    default:
                        print("room event: ", event.roomId, event.eventType, event.type, event.content)
                    }
                 }else{
                     print("room event: ", event)
                 }
                 break

            case .backwards:
                 // Events that occurred in the past will come here when requesting pagination.
                 // roomState contains the state of the room just before this event occurred.
                 break
           }
    }
}
```

If you are only interested in some specific type of event, you can set the value of the parameter `types`:

```swift
session.listenToEvents([MXEventType.roomMessageFeedback,
                        MXEventType.roomMessage
]){ event, direction, customObject in
}
```

#### Create a private room and chat with a user

If you want to chat with a user, you can create a private room.

```swift
let user = "THE_USER_ID_YOU_WANT_TO_CHAT_WITH"

let params = MXRoomCreationParameters()
params.inviteArray = [user]
params.isDirect = true
params.visibility = "private"
params.preset = "trusted_private_chat"
let dic:[String:Any] = [
    "type": "m.room.guest_access","state_key": "",
]
params.name = "THE_NAME_YOU_WANT"
params.roomType = "m.room.guest_access"
params.initialStateEvents =  [ dic ]
params.creationContent = [ "guest_access": "can_join"]

client.createRoom(parameters: params){ response in
    switch response{
    case .failure(let error):
        print(error)
        return
    case .success(let resp):
        return
    }
}
```

#### Create a room

Now you can create a room to chat with a specific interest group.

```swift
// room parameters
let params = MXRoomCreationParameters()
params.name = "THE_ROOM_NAME"

client.createRoom(parameters: params) { response in
    switch response{
        case .failure(let error):
            print(error)
            return
        case .success(let resp):
            print("room id: ", resp.roomId!)
            return
        }
}
```

#### Invite users with the same interest

It's time to invite users to the room you created.

```swift
let roomId = "THE_ROOM_ID";
let userId = "THER_USER_ID_YOU_WANT_INVITE";

client.invite(MXRoomInvitee.userId(userId), toRoom: roomId) { response in
    switch response{
        case .success():
            print("invite user successfully")
            return
        case .failure(let error):
            print(error)
            return
    }
}
```

#### Get messages of a room

To get messages, we need to reuse the `mxSession` instance created before:

```swift
// Retrieve the room from its room id
let room = mxSession.room(withRoomId: "YOUR_ROOM_ID")

// Add a listener on events related to this room
_ = room?.liveTimeline.listenToEvents { (event, direction, roomState) in
    switch direction {
    case .forwards:
        // Live/New events come here
        break

    case .backwards:
        // Events that occurred in the past will come here when requesting pagination.
        // roomState contains the state of the room just before this event occurred.
        break
    }
}
```

#### Post a message to a room

To post a message, we create a content message and specify a room.

```swift
client.sendTextMessage(toRoom: "YOUR_ROOM_ID", text: "Hello World!") { (response) in
    if case .success(let eventId) = response {
        // eventId is for reference
        // If you have registered events listener like in the previous use case, you will get
        // notification for this event coming down from the server events stream and
        // now handled by MXSession.
    }
}
```
