iosswiftamazon-web-servicesejabberdadium

Connecting iOS app to Ejabberd Server hosted on Amazon


I hosted Ejabberd chat server on Amazon and added two user there, when I tried to connect Ejabberd server through Adium, it asks for certificate then only it gets connected, now I'm developing chat application in Swift using Ejabberd server and XMPP, I configured all code , passed host name and port no: 5222, but its not connecting to server. Should I need to write program to fetch server certificate and pass my computer certificate (.p12) file to server?

NOTE: I configured Ejabberd server in localhost and through iOS Swift Code, it's working perfectly when I send message from iOS app then it shows in Adium and when Adium user send message then I go to Ejabberd Web Admin Panel and can check offline Messages.

Here is the code in Swift for connecting Ejabberd hosted on Amazon:

//
//  AppDelegate.swift
//  Thanks to Process One for this.

import UIKit
import XMPPFramework

protocol ChatDelegate {
    func buddyWentOnline(_ name: String)
    func buddyWentOffline(_ name: String)
    func didDisconnect()
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, XMPPRosterDelegate, XMPPStreamDelegate {

    var window: UIWindow?
    var delegate:ChatDelegate! = nil
    let xmppStream = XMPPStream()
    let xmppRosterStorage = XMPPRosterCoreDataStorage()
    var xmppRoster: XMPPRoster

    override init() {
        xmppRoster = XMPPRoster(rosterStorage: xmppRosterStorage)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        DDLog.add(DDTTYLogger.sharedInstance())

        setupStream()

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        disconnect()
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        connect()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

    //MARK: Private Methods
     func setupStream() {//fileprivate
        //xmppRoster = XMPPRoster(rosterStorage: xmppRosterStorage)
        xmppRoster.activate(xmppStream)
        xmppStream?.addDelegate(self, delegateQueue: DispatchQueue.main)
        xmppRoster.addDelegate(self, delegateQueue: DispatchQueue.main)
    }

     func goOnline() { //fileprivate
        let presence = XMPPPresence()
        let domain = xmppStream?.myJID.domain

        if domain == "gmail.com" || domain == "gtalk.com" || domain == "talk.google.com" {
            let priority = DDXMLElement.element(withName: "priority", stringValue: "24") as! DDXMLElement
            presence?.addChild(priority)
        }

        xmppStream?.send(presence)
    }

     func goOffline() { //fileprivate
        let presence = XMPPPresence(type: "unavailable")
        xmppStream?.send(presence)
    }

    func connect() -> Bool {
        xmppStream.hostName = "amazon hosted ejabber ip address"
        xmppStream.hostPort=5222
        if !(xmppStream?.isConnected())! {
            let jabberID = UserDefaults.standard.string(forKey: "userID")
            let myPassword = UserDefaults.standard.string(forKey: "userPassword")

            if !(xmppStream?.isDisconnected())! {
                return true
            }
            if jabberID == nil && myPassword == nil {
                return false
            }


            xmppStream?.myJID = XMPPJID.init(string: jabberID)

            do {
                try xmppStream?.connect(withTimeout: XMPPStreamTimeoutNone)
                print("Connection success")
                return true
            } catch {
                print("Something went wrong!")
                return false
            }
        } else {
            return true
        }
    }

    func disconnect() {
        goOffline()
        xmppStream?.disconnect()
    }

    //MARK: XMPP Delegates
    func xmppStreamDidConnect(_ sender: XMPPStream!) {
        do {
            try xmppStream?.authenticate(withPassword: UserDefaults.standard.string(forKey: "userPassword"))
        } catch {
            print("Could not authenticate")
        }
    }

    func xmppStreamDidAuthenticate(_ sender: XMPPStream!) {
        goOnline()
    }

    func xmppStream(_ sender: XMPPStream!, didReceive iq: XMPPIQ!) -> Bool {
        print("Did receive IQ")
        return false
    }

    func xmppStream(_ sender: XMPPStream!, didReceive message: XMPPMessage!) {
        print("Did receive message \(message)")
    }

    func xmppStream(_ sender: XMPPStream!, didSend message: XMPPMessage!) {
        print("Did send message \(message)")
    }

    func xmppStream(_ sender: XMPPStream!, didReceive presence: XMPPPresence!) {
        let presenceType = presence.type()
        let myUsername = sender.myJID.user
        let presenceFromUser = presence.from().user

        if presenceFromUser != myUsername {
            print("Did receive presence from \(presenceFromUser)")
            if presenceType == "available" {
                delegate.buddyWentOnline("\(presenceFromUser)@gmail.com")
            } else if presenceType == "unavailable" {
                delegate.buddyWentOffline("\(presenceFromUser)@gmail.com")
            }
        }
    }

    func xmppRoster(_ sender: XMPPRoster!, didReceiveRosterItem item: DDXMLElement!) {
        print("Did receive Roster item")
    }
}

Solution

  • Finally i managed to solve this issue and i am really amaze to implement chat application using Ejabberd server hosted on Amazon.

    Issue :

    1. When i was running my application , it was not connecting ?

    Answer : Certificate issue (Server - client side certificate handshake resolves issue)

    2. Unable to fetch online buddy ? Answer : i used Adium to make all user online and then run my application and it works like a charm.

    Great learning for me for this application. If any1 having any issue with chat ,feel free to comment i am looking forward to help. Thanks