🎉 New release for Pusher Chatkit - Webhooks! Extend your in-app chat functionality

Extensible API for in-app chat


Build scalable realtime features


Programmatic push notifications



Read the docs to learn how to use our products


Explore our tutorials to build apps with Pusher products


Reach out to our support team for help and advice

Sign in
Sign up

Creating a Laravel Logger - Part 5: Creating our iOS application

  • Neo Ighodaro
March 28th, 2019
For this part of the series you will need the latest version of Xcode installed on your machine.

In this tutorial of the series, we will build an iOS app for our logger system. Just like the Android app, it will display logs in a list and receive notifications, particularly for error logs.

Here is the demo of what we will build:

Let’s get started.

In the previous part of the series, we created the Android client for our log monitor. It helps us visualize logs and also displays push notifications for error messages.


To follow along with this series you need the following things:

Creating the project

Open Xcode and create a new iOS project. Choose the Single View App template like this:

After this, you then enter a product name - for example, LoggerClient, team name, and organization details. Choose Swift as the default language and select Next. Select the directory you want your app to be stored and wait for the project to complete its initial build.

Once the project is ready, close Xcode, and create a Podfile in the root directory of your app. To do this, run the following command in the root directory of your application:

    $ pod init

We will insert the dependencies we will use in this project into this file. The Podfile should look like this:

    # File: ./Podfile
    target 'LoggerClient' do

      pod 'PusherSwift'
      pod 'PushNotifications'

Here, we added dependencies for Pusher Channels and Pusher Beams. Next, run this command still in the main app directory:

    $ pod install

This will install the dependencies in your app. Once the installation is complete, open the .xcworkspace file located in the folder of your project in Xcode. This was generated after you installed the Podfile.

Now, we are ready to start building.

Implementing push notifications

To enable notifications on our app, we need to set up a few things. Login to your Apple Developer Account and create an APNs (Apple Push Notification service) key in the keys section. After creating the key, download it.

Next, open the Pusher Beams instance created earlier in the series and select the iOS quick guide. Configure it with your key and Team ID from your developer account.

First, we need to add the capability to our application. As seen below, you need to turn on the Push Notifications capability in the Capabilities tab of your target.

This will create a *.entitlements file in your workspace. Next, open the AppDelegate file and replace the contents with the contents below:

    import UIKit
    import PushNotifications

    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        let pushNotifications = PushNotifications.shared

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            pushNotifications.start(instanceId: PUSHER_BEAMS_INSTACE_ID)
            try? self.pushNotifications.subscribe(interest: "log-interest")
            return true

        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

Above, we use the PushNotifications package to register the device to receive push notifications. This will trigger a one-time-only prompt for permission to allow your application to send push notifications. If the user grants this permission, your application will be able to send push notifications.

Replace the placeholder above with the credentials on your Pusher Beams dashboard.

Implementing realtime logs

The next thing we will do is implement realtime logs in the app. Open the Main.storyboard file and delete the default ViewController scene. Drag a TableViewController element and drop on the empty light grey area. You should now have a bare TableViewController like this:

Set the new controller as the initial controller in the attributes inspector.

Go to your ViewController class and replace the UIViewController class with UITableViewController like this:

    class ViewController: UITableViewController {

Go back to your Main.storyboard file and choose a custom class for the view controller in the identity inspector. Select the just updated ViewController class.

Now, we will design how each row on the table view will look like. Drag an ImageView and a label to the table view like this:

Now, we will add constraints to them. Select the imageview and add the following constraints:

From the image, we added a left margin of 20, and the image is constrained to the label with a spacing of 10. We also gave the image a fixed width and height of 20. We also made sure the image is centered vertically

Next, let us add constraints for the label. Just like you did for the imageview in the above image, add a vertical alignment to the label. Next, we add a constraint to the right of the parent view and a spacing of 10.

Still for the label, set the Line Break to word wrap and Lines to 0 in the attributes inspector like this:

This is to enable our text to wrap properly in case there are excesses. Now, let us create some other helping files for our TableView. The first will be a model class named LogModel. Create a new class with the name and paste this:

    // File: ./LogModel.swift
    import Foundation
    import UIKit

    class LogModel {

        var logMessage: String?
        var logLevel: String?


This class represents the data each row will hold which is the log message and the log level. Next, we will create a class for the table cell. Create a class called TableCell and paste this:

    // File: ./TableCell.swift
    import Foundation
    import UIKit

    class TableCell: UITableViewCell {

        @IBOutlet weak var labelLogMessage: UILabel!

        @IBOutlet weak var imageLogLevel: UIImageView!

        func setValues(item:LogModel) {

            labelLogMessage.text = item.logMessage
            imageLogLevel.image = UIImage(named:"LogLevel")!.withRenderingMode(.alwaysTemplate)

            if (item.logLevel == "warning") {
                imageLogLevel.tintColor = UIColor.yellow
            } else if (item.logLevel == "info") {
                imageLogLevel?.tintColor = UIColor.blue
            } else if (item.logLevel == "error") {
                imageLogLevel.tintColor = UIColor.red

You should link the @IBOutlet properties to the elements on the layout.

In this class, we created a setValues method that assigns the values from our model to the UI elements. We used an image asset (a rectangular object) called LogLevel. Depending on the log level, we change the color of the image. You can get the image from the GitHub repo for this article.

Now, go to the table view in the Main.storyboard file and select the just created TableCell as its class.

Now, open your ViewController class and replace this:

    // File: ./ViewController.swift
    import UIKit
    import PusherSwift

    class ViewController: UITableViewController {

        var logMessageList = [LogModel]() {
            didSet {

        var pusher:Pusher!

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

        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let currentItem = logMessageList[indexPath.row]
            let logCell = tableView.dequeueReusableCell(withIdentifier: "logCell") as! TableCell

            logCell.setValues(item: currentItem)

            return logCell

        override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 50

        override func viewDidLoad() {

In the snippet above, we first declared a list named logMessageList for items in the table view. Whenever this list is modified, we reload the table view. Next, we declared a pusher variable which we will use shortly.

We have three methods here that affect the table view, the first one is to tell the size of the table view - here, we returned the size of the logMessageList. The next method maps data from the list to each cell and the last method sets the height size for each cell.

Next, in our viewDidLoad method, we called a method setupPusher. Create the method inside the class like so:

    func setupPusher(){
        let options = PusherClientOptions(
            host: .cluster("PUSHER_APP_CLUSTER")

        pusher = Pusher(
            key: "PUSHER_APP_KEY",
            options: options

        let channel = pusher.subscribe("log-channel")

        let _ = channel.bind(eventName: "log-event", callback: { (data: Any?) -> Void in
            if let data = data as? [String : AnyObject] {
                let logModel = LogModel()
                logModel.logLevel = data["loglevel"] as? String
                logModel.logMessage = data["message"] as? String

This snippet initializes Pusher and listens to the relevant channel for updates. When we get a new object, we map it to our LogModel class and add it to the logMessageList.

Replace the placeholders with the credentials from your dashboard.

When you run your app, you should see something like this:


In this part, we have created the iOS client for our logging monitoring. In the app, we display all logs being sent through the channels and the error logs are also sent as push notifications. In the last part of the series, we will create the web application for the log monitor.

The source code is available on GitHub.

Clone the project repository
  • Android
  • Beams
  • iOS
  • Kotlin
  • Laravel
  • PHP
  • Swift
  • Vue.js
  • Beams
  • Channels


  • Channels
  • Chatkit
  • Beams

© 2019 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 160 Old Street, London, EC1V 9BW.