We thought we’d create a walkthrough of how to easily build an iOS chat app with Pusher. Together we will build a group chat application, leading you through how to use Pusher to send and show realtime messages in your UI.

The app we’re building

The app we’re building is a simple chat application that uses Pusher to send and receive messages.
It has two screens – the “Login” screen where we enter our Twitter username, and the “Chat” screen where we do the messaging.

Setting up our project with XCode

If you haven’t yet, create a new application on XCode. By default the wizard offers you to create a Single View Application for iOS, and that’s perfectly fine. Once you’ve done that, you’ll need to prepare the dependencies for the app. The dependencies you need are Pusher Swift for interaction with Pusher, and AlamofireImage for performing network requests, and loading images over the network.

The easiest way install dependencies is by using CocoaPods. If you don’t have CocoaPods installed you can install them via RubyGems.

gem install cocoapods

Then configure CocoaPods in our application. First initialise the project by running this command in the top-level directory of your XCode project:

pod init

This will create a file called Podfile. Open it, and make sure to add the following lines specifying your app’s dependencies:

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'Pusher Chat Sample iOS' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Pusher Chat Sample iOS
  pod 'PusherSwift'
  pod 'AlamofireImage' //need that for networking

end

And then run pod install to download and install both dependencies.

pod install

CocoaPods will ask you to close XCode if it’s currently running, and open the newly generated .xcworkspace file. Do this now, and XCode will open with your project configured.

Creating the Login View

For our login feature we’ll just create a simple page with a field to enter a twitter handle and a login button.

First rename our scene to “Login Scene”, and then drag the two elements onto it.
Also rename the ViewController to LoginViewController.

Control-drag the each element into the LoginViewController class to create the IBOutlet (for the TextView) and the IBAction for the button.

Name the IBOutlet twitterHandle and IBAction loginButtonClicked.

In your LoginViewController.swift add the following logic to the loginButton function:


@IBAction func loginButtonClicked(_ sender: Any) { if(twitterHandle.hasText){ let messagesViewController = self.storyboard?.instantiateViewController(withIdentifier: "chatViewController") as! ChatViewController messagesViewController.twitterHandle = twitterHandle.text! self.present(messagesViewController, animated:true) } else{ print("No text in textfield") } }

This will grab the current text in the twitterHandle field and set it to the ChatViewController, and transition to the Chat screen.

Chat View

But the ChatViewController doesn’t exist yet! Create a new ViewController in the Storyboard and the corresponding ChatViewController.swift class.
Add to it a TableView, a Text Field, and a Button as in the example.

Listening to messages

We will listen to new messages in realtime by subscribing to the chatroom channel and listening to events tagged new_message.
Pusher channels can support unlimited number of message types, but in our case we are only interested the single one.

In viewDidLoad create your Pusher instance – and copy your setup details from the Pusher Dashboard. It shoud look like this:

pusher = Pusher(
          key: "abcdefghijklmnopqrstuvwxyz"
)

Then subscribe to the chatroom channel, and bind to the new_message events, printing their messages to the console. Lastly, connect to Pusher.

let channel = pusher!.subscribe("chatroom")
let _ = channel.bind(eventName: "new_message", callback: { (data: Any?) -> Void in

    if let data = data as? [String: AnyObject] {

        let text = data["text"] as! String
        let author = data["name"] as! String
        print(author + ": " + text)
    }
})
pusher!.connect()

Now that we’ve subscribed and listening to the events, we can send some events to test it out. The easiest way to do this is by using Pusher’s Debug Console – in your app’s Dashboard. Have the application running – Simulator is fine.
Click Show Event Creator button, and change the name of Channel to chatroom, and change the Event to new_message – what we’re listening to in the app.
Now change the Data field to something like:

{
  "name": "John",
  "text": "Hello, World!"
}

And click Send event. In the XCode’s console, you should see the message printed out:

John: Hello, World!

Presenting messages in a table

Now, let’s show the messages as they arrive in the UITableView.
We will create a Prototype cell in the UITableView in the Storyboard, and specify a class for it.

Create a MessageCell.swift class and make it extend UITableViewCell. This will represent a single chat message as a row in our table. Drag the outlets for authorAvatar, authorName, and messageText into the class. This

import Foundation
import UIKit

class MessageCell: UITableViewCell {
    @IBOutlet var authorAvatar: UIImageView!
    @IBOutlet var authorName: UILabel!
    @IBOutlet var messageText: UILabel!
}

Now create a Message.swift which will hold a struct representing a single Message object. It just needs to hold two strings, for the author and message.

import Foundation

struct Message {

    let author: String
    let message: String

    init(author: String, message: String) {
        self.author = author
        self.message = message
    }
}

Back in the ChatViewController.swift, make the class implement the protocols UITableViewDataSource and UITableViewDelegate alongside UIViewController:

class ChatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

To make it compile, you’ll need to implement the following methods – first one to let the tableView know how many items it holds:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
       return array.count
   }

And the second one that will create a MessageCell object:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessageCell
    return cell
}

Then we need to add some logic that will actually present the data in a cell. Add these lines to the second method:

let message = array.object(at: indexPath.row) as! Message

cell.authorName.text = message.author
cell.messageText.text = message.message

let imageUrl = URL(string: "https://twitter.com/" + message.author + "/profile_image")
cell.authorAvatar.af_setImage(withURL: imageUrl!)

First we set up the text in the author and message labels, and lastly we use the AlamofireImage library to load the image from Twitter avatar into the authorImage field.

Sending messages from the app

Building the serverside component in NodeJS

So far, we’ve created a client that receives items. But what about sending them? We’ll do that next.
First, we’ll need a server-side component that receives messages and sends them back to Pusher.

We prepared a simple NodeJS application that will serve that purpose. You can find it here.

First clone the repository and CD into its directory. Then run npm install to setup dependencies.

Then open app.js and change the Pusher initialisation fields there to include your App ID, key and secret. You can copy these from your Pusher Dashboard – the Getting Started tab will have everything you need.

Once you’ve done that you can launch the app by running node app.js.

If your iOS app is running on your simulator, and your Node app is running the server, you should be able send a test message via the cURL command:

$ curl -X "POST" "http://localhost:3000/messages" -H "Content-Type: application/json; charset=utf-8" -d $'{"name": "Pusher","text": "Hello, Node!"}'

If everything works as it should, you should see the new message appear in your app.

Building the app component

The last thing to do is to create the function that triggers and sends the message to us.

First make sure your Text Field and Button have their corresponding outlets in ChatViewController.swift:

@IBOutlet var message: UITextField!
@IBAction func send(_ sender: Any) {

       if(message.hasText){
           postMessage(name: twitterHandle, message: message.text!)
       }
}

Finally, we can implement the postMessage function that calls our NodeJS endpoint to trigger a new message over Pusher:

func postMessage(name: String, message: String){

        let params: Parameters = [
            "name": name,
            "text": message
        ]

        Alamofire.request(ChatViewController.MESSAGES_ENDPOINT, method: .post, parameters: params).validate().responseJSON { response in

            switch response.result {

            case .success:
                print("Validation successful")
            case .failure(let error):
                print(error)
            }
        }
}

Try it out!

If you are running the Node server locally XCode might not allow you to make the request. You can get around this by adding App Transport Security Settings to your Info.plist file and set Allow Artibrary Loads to YES.

Get Pushing

Hopefully you have found this a straightforward example of how to build an iOS chat app with Pusher. There are many ways you can extend this tutorial for an improved application:

  • Use Pusher client events to send messages from one client to another. You could use our webhooks to notify your server when messages are sent, allowing you to persist them in your database.
  • Use Pusher presence channels to create live user lists and show who’s online in realtime.
  • Use our REST API to determine whether a user is connected to Pusher. If they are, go ahead and send them a message as normal. If not, send them a native push notification leading them back to your app.

Even with such a basic app, hopefully I have shown you how easy and few lines of code it is to drop in Pusher to any iPhone app. Feel more than free to let us know what you end up building with Pusher and iPhone!