iOS Chat App with XMPP framework
Tags: xmpp, ios, instantmessaging
Published: 2019-12-21 07:50:52

Wants to build Chat App for iOS?

Lets gets started
XMPP stands for Xtensible Messaging & Presence Protocol. 

Things required ?
1. IM Server (I prefer MongooseIM)
2. User (Account created)

You can download MongooseIM Package here & Install package
https://www.erlang-solutions.com/resources/download.html

Details for installation can be found here https://mongooseim.readthedocs.io/en/latest/user-guide/Getting-started/

On installation completes launch Terminal & execute following command 
`$ mongooseimctl start`

then Check status
`$ mongooseimctl status`


When All thats done. You need a user, head down below & create user

`$ mongooseimctl register <user> <host> <password>`

Eg: `$ mongooseimctl register user1 localhost qwerty`

You can verify user creation `$ mongooseimctl registered_users localhost`

Till now server config & user creation completed.

Before jumping into code part, lets understand following things
1. JID
2. Stanza & its type.
3. Stream.
 

 1. **JID**: is something by which each individual is uniquely identified is XMPP. It does looks like this
`username@hostname/resource`
username: is local part
hostname: is domain part
resource: is resource part which is optional in many cases

 2. **Stanza**: is name of XML tag/piece that sends & received. Basic Stanza's are < message > < presence > & < iq >, details will be mentioned about them, if required in future

 3. **Stream**: is entry point for interprocess communication to start on shared file called Socket, which happens by < stream > tag.


We shall start working on iOS App.
I hope you guys knows how to create Xcode iOS Project & Pod setup.

In Podfile  ` pod 'XMPPFramework' `
then run `pod install`

Create XMPPController.swift file & make a singleton object.

    class XMPPController: NSObject {
        static let sharedInstance = XMPPController()
    }

Now declare an XMPPStream instance & intilize it in `init()`

    var stream: XMPPStream?
    override init() {
      self.stream = XMPPStream()
      super.init()
    }

Also declare following vars.

    var hostName: String?
    var userJID: XMPPJID?
    var hostPort: UInt16?
    var password: String?
 

Declare a connect function as below

    func connect(withHostName name: String, userJID jid: String, hostPort port: UInt16, password pwd: String) {

        guard let uJID = XMPPJID(string: jid) else {
            return
        } 

        hostName    = name
        userJID     = uJID
        hostPort    = port
        password    = pwd
        
        // Stream Configuration
        stream?.hostName = name
        stream?.myJID = uJID
        stream?.hostPort = port
        stream?.startTLSPolicy = .allowed
        
        if stream!.isDisconnected {
            do {
                try stream?.connect(withTimeout: 10)
            }
            catch let e {
                print(e.localizedDescription)
            }
        }
    }


Once we reached till here, we have forgot most important thing.
without confirming delegate of stream our `XMPPController` wont able to receive any callbacks, add following lines in `init`

    self.stream?.addDelegate(self, delegateQueue: DispatchQueue.main)



`XMPPStreamDelegate` as set of delegate functions among them we will use only couple of, add following code as below

    extension XMPPController: XMPPStreamDelegate {
        func xmppStreamDidConnect(_ sender: XMPPStream) {
           print("Stream Connected")
           try! stream?.authenticate(withPassword: password!)
        }
     
        func xmppStreamDidAuthenticate(_ sender: XMPPStream) {
           print("Stream: Authnticated")
           stream?.send(XMPPPresence())
        }
    }


Once `xmppStreamDidConnect(:XMPPStream)` is connected, we are making sure that authentication should initiate & on authentication `xmppStreamDidAuthenticate(:XMPPStream)` will receive callback


Entire code is available on github repo
https://github.com/momin96/Mobile-Chat-App