July 18, 2020

How to build a chat app in iOS Swift

Nabil Kazi

Introduction

There is a tremendous increase in chat applications in the market. The current Covid-19 situation worldwide also played its part in this. Many companies are leveraging existing applications to manage their internal communication. We also saw a rise in custom chat applications. More and more communication applications are being released each day. There cannot be a better time to learn and build one yourself!


CometChat

If you have never heard of CometChat, the headline on it’s website sums up nicely in one line. Text chat & video calling for your website and apps. It has 2 variants, CometChat Go and CometChat Pro.

  • Go is used for drag and drop chat plugin for your websites and no-code solutions.
  • Pro gives you access to its APIs, SDKs, Components to build your solution with bare minimum development. You can read more about CometChat Pro here.


What we’ll cover in this article?


We’ll be building an iOS chat application in Swift from scratch. From adding CometChat SDK to live chatting!


Below is the overview of what we’ll be doing -

  • Adding the CometChat SDK and configuring our project.
  • Implementing user registration
  • Setting up conversations & chat screens
  • Live chat in action!


We would be leveraging CometChat’s Swift UI Kit to build our chat app. I’ll show you how this makes the overall development a breeze!

Let’s start building…

Step 1 - Setting up CometChat


Before starting with CometChat, it is important to understand how CometChat works! The Key Concepts page of CometChat documentation can help you with that.

Before diving into the code, we’ll need to setup CometChat in our application. CometChat Quick Start document does a wonderful job in explaining the steps in detail.  


We’ll outline the steps from the above document -

  1. Create your CometChat Pro account
  2. Get your Application API Keys
  3. Add the CometChat Dependency in your Application by adding its Pod
  4. Add the CometChat Swift UI Kit Library
  5. Add Application API Keys, App ID and region and initialize CometChat SDK


Step 2 - Registering / Logging new User


CometChat key concepts page states that -

    CometChat does not handle user management. You must handle user registration and login at your end. Once the user is logged into your app/site, you can log in the user to CometChat programmatically. So the user does not ever directly login to CometChat.


It means in the production environment, you’d either be using your custom back-end application or Firebase for user management. This is where you’d store all the registered users of your app.


So, a typical flow would be →

The user opens your app’s registration page. When the user clicks submit →

  1. You would call your back-end API to register the User in your database.
  2. After a successful response from your API, you would then create the user in CometChat using its createUser API.



But, for the sake of simplicity, In this tutorial, we would

not be using any back-end service or Firebase. We would proceed with the CometChat’s user creation.


Our Registration page asks for User’s name and mobile.

We then concatenate name’s first letter with the mobile number to create our unique id i.e UID.

Now that we have our user’s name and UID, we use CometChat’s createUser API to create the user in our CometChat’s database.


You can also view your User in the CometChat Dashboard. Then in the final step, we call CometChat’s login API to log the user into our app.




Let’s see the entire process in code…

{% c-block language="swift" %}
@IBAction func signInTapped(_ sender: Any) {
 let uid = "\(nameTextField.text!.first!)\(mobileTextField.text!)"
   registerUser(uid: uid , name: nameTextField.text!)
}
private func registerUser(uid: String, name: String){
   showActivityIndicator()
   let newUser : User = User(uid: uid, name: name)
   CometChat.createUser(user: newUser, apiKey: Constants.apiKey, onSuccess: { (User) in
       print("User created successfully. \(User.stringValue())")
       self.hideActivityIndicator()
       if CometChat.getLoggedInUser() == nil {
           self.loginUser(uid: uid)
       }  
     }) { (error) in
       print("The error is \(String(describing: error?.errorDescription))")
       self.hideActivityIndicator()
   }
}
private func loginUser(uid: String){
   showActivityIndicator()
   CometChat.login(UID: uid, apiKey: Constants.apiKey, onSuccess: { (user) in
       print("Login successful : " + user.stringValue())
       self.hideActivityIndicator()
   }) { (error) in
       print("Login failed with error: " + error.errorDescription)
       self.hideActivityIndicator()
   }
}
{% c-block-end %}


Step 3 - Setting up Conversation List View


Once the user logs in the app, we would be showing the user’s latest conversations. This screen contains a list of all his one-to-one and group conversations.  


For this, we would first create a ConversationsVC by extending it from CometChatConversationList.


CometChatConversationList is a part of CometChat’s Swift UI Kit. We won’t have to create UITableView, UITableViewCell or any custom development of any sorts to display our conversation list. We won’t even have to call the API ourselves!

Whatt??? Yes, CometChat’s UI Kit handles it all for us.


Tapping on any conversation would take you to its Chat screen. This behavior is also built in into the UI Kit library.



{% c-block language="swift" %}
import CometChatPro
class ConversationsVC: CometChatConversationList {
   static func storyboardInstance() -> ConversationsVC? {
       let storyboard = UIStoryboard(name: "Main" ,bundle: nil)
       return storyboard.instantiateViewController(withIdentifier: "ConversationsVC") as? ConversationsVC
   }
   override func viewDidLoad() {
       super.viewDidLoad()
}
}
{% c-block-end %}


Now, we would update our Login function to open this ConversationsVC after successful login. Let’s take a look at our final updated Registration Screen code -


{% c-block language="swift" %}
import CometChatPro
class RegistrationLoginVC: UIViewController {
   @IBOutlet weak var signIn: UIButton!
   @IBOutlet weak var nameTextField: UITextField!
   @IBOutlet weak var mobileTextField: UITextField!    
   @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
   override func viewDidLoad() {
       super.viewDidLoad()
   }
   @IBAction func signInPressed(_ sender: Any) {
       let uid = "\(nameTextField.text!.first!)\(mobileTextField.text!)"
       registerUser(uid: uid , name: nameTextField.text!)
   }
   private func registerUser(uid: String, name: String){
       showActivityIndicator()
       let newUser : User = User(uid: uid, name: name)
       CometChat.createUser(user: newUser, apiKey: Constants.apiKey, onSuccess: { (User) in
           print("User created successfully. \(User.stringValue())")
           self.hideActivityIndicator()
           if CometChat.getLoggedInUser() == nil {
               self.loginUser(uid: uid)
           }
         }) { (error) in
           print("The error is \(String(describing: error?.errorDescription))")
           self.hideActivityIndicator()
       }
   }
   private func loginUser(uid: String){
       showActivityIndicator()
       CometChat.login(UID: uid, apiKey: Constants.apiKey, onSuccess: { (user) in
           print("Login successful : " + user.stringValue())
           self.hideActivityIndicator()
           self.openChats()
       }) { (error) in
           print("Login failed with error: " + error.errorDescription);
           self.hideActivityIndicator()
       }
   }
   private func openChats(){
       DispatchQueue.main.async {
           let conversationList = ConversationsVC.storyboardInstance()
           let navigationController = UINavigationController(rootViewController:conversationList!)
           conversationList!.set(title:"Chats", mode: .automatic)
           self.present(navigationController, animated:true, completion:nil)
       }
   }
   private func showActivityIndicator(){
       DispatchQueue.main.async {
           self.activityIndicator.startAnimating()
       }
   }
   private func hideActivityIndicator(){
       DispatchQueue.main.async {
           self.activityIndicator.stopAnimating()
       }
   }
}
{% c-block-end %}



Step 4 - Select a new user to start Chatting!

We need to add a feature where user can select from existing users of the app and start chatting. For this, we would create a “New Chat” button in ConversationsVC


On click of the button, we would be opening CometChatUserList.

CometChatUserList is also a part of CometChat’s Swift UI Kit. Similar to CometChatConversationList,  we won’t have to create UITableView, UITableViewCell or any custom development of any sorts to display our user list. We won’t even have to call the API ourselves!


This screen will display a list of all the users who have registered with your application.  We can open the CometChatUserList screen using the below code.


{% c-block language="swift" %}
let userList = CometChatUserList()
let navigationController = UINavigationController(rootViewController:userList)
userList.set(title:"Contacts", mode: .automatic)
self.present(navigationController, animated:true, completion:nil)
{% c-block-end %}


Once the CometChatUserList screen opens, tapping on any of the contacts takes you by default to its chat screen. This behavior is also built-in into the UI Kit library.


Let’s have a look at our updated ConversationsVC code with the implementation of “New Chat” button -

{% c-block language="swift" %}
import CometChatPro
class ConversationsVC: CometChatConversationList {
 @IBOutlet weak var newChatButton: UIButton!
   static func storyboardInstance() -> ConversationsVC? {
       let storyboard = UIStoryboard(name: "Main" ,bundle: nil)
       return storyboard.instantiateViewController(withIdentifier: "ConversationsVC") as? ConversationsVC
   }
   override func viewDidLoad() {
       super.viewDidLoad()
   }
   public override func viewDidAppear(_ animated: Bool) {
       super.viewDidAppear(animated)
       newChatButton.superview?.bringSubviewToFront(newChatButton)
   }
   @IBAction func newChatTapped(_ sender: Any) {
       openContactsList()
   }
   private func openContactsList(){
       DispatchQueue.main.async {
           let userList = CometChatUserList()
           let navigationController = UINavigationController(rootViewController:userList)
           userList.set(title:"Contacts", mode: .automatic)
           self.present(navigationController, animated:true, completion:nil)
       }
   }
}
{% c-block-end %}


Step 5 - Start Chatting!

I am kidding! There’s no step 5 when you are using CometChat’s UI Kit!

Once you click on an item on the Conversations Screen or Contact Selection screen, you are by default routed to CometChat’s Chat Message screen. This screen comes implemented with the UI Kit library itself. It contains a list of all the messages, images and the history of entire chat with that person.

No UI development needed, no API calls needed! Get on with your chatting…!

That’s it! You have your working Chat application ready in minutes! Select a user from Conversations Screen or Contacts Screen and start chatting!

Conclusion

CometChat makes it very easy to implement your Chat application. It’s UI Kit gives you predefined screens with all its working. No need to call APIs to fetch the conversations, or chats or users.

If you need more detailed information on CometChat’s Swift UI Kit. 3 different ways in which you can leverage it to make a chat app. You can take a look at my earlier tutorial - “Add chat to your Swift app, Quick!


CometChat caters to your varied needs. Creating a stand-alone chat application or a chat module in your existing app, you name it! You can leave the working of Chat to us and spend more time working on your business logic instead.


Feel free to reach out if you face issues in the implementation or have some quick ideas. I’ll be happy to discuss