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

Introduction

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:

laravel-log-5-1

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.

Requirements

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:

laravel-log-5-2

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:

1# File: ./Podfile
2    target 'LoggerClient' do
3      use_frameworks!
4    
5      pod 'PusherSwift'
6      pod 'PushNotifications'
7    end

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. Refer to Beams docs for more details.

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.

laravel-log-5-3

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

1import UIKit
2    import PushNotifications
3    
4    @UIApplicationMain
5    class AppDelegate: UIResponder, UIApplicationDelegate {
6        var window: UIWindow?
7        let pushNotifications = PushNotifications.shared
8    
9        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
10            pushNotifications.start(instanceId: PUSHER_BEAMS_INSTACE_ID)
11            pushNotifications.registerForRemoteNotifications()
12            try? self.pushNotifications.subscribe(interest: "log-interest")
13            return true
14        }
15    
16        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
17            pushNotifications.registerDeviceToken(deviceToken)
18        }
19    }

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:

laravel-log-5-4

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

laravel-log-5-5

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:

laravel-log-5-6

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

laravel-log-5-7

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

laravel-log-5-8

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.

laravel-log-5-9

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

laravel-log-5-10

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:

1// File: ./LogModel.swift
2    import Foundation
3    import UIKit
4    
5    class LogModel {
6    
7        var logMessage: String?
8        var logLevel: String?
9    
10    }

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:

1// File: ./TableCell.swift
2    import Foundation
3    import UIKit
4    
5    class TableCell: UITableViewCell {
6    
7        @IBOutlet weak var labelLogMessage: UILabel!
8    
9        @IBOutlet weak var imageLogLevel: UIImageView!
10    
11        func setValues(item:LogModel) {
12    
13            labelLogMessage.text = item.logMessage
14            imageLogLevel.image = UIImage(named:"LogLevel")!.withRenderingMode(.alwaysTemplate)
15    
16            if (item.logLevel == "warning") {
17                imageLogLevel.tintColor = UIColor.yellow
18            } else if (item.logLevel == "info") {
19                imageLogLevel?.tintColor = UIColor.blue
20            } else if (item.logLevel == "error") {
21                imageLogLevel.tintColor = UIColor.red
22            }
23        }
24    }

NOTE: 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.

laravel-log-5-11

Now, open your ViewController class and replace this:

1// File: ./ViewController.swift
2    import UIKit
3    import PusherSwift
4    
5    class ViewController: UITableViewController {
6    
7        var logMessageList = [LogModel]() {
8            didSet {
9                self.tableView.reloadData()
10            }
11        }
12    
13        var pusher:Pusher!
14    
15        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
16            return logMessageList.count
17        }
18    
19        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
20            let currentItem = logMessageList[indexPath.row]
21            let logCell = tableView.dequeueReusableCell(withIdentifier: "logCell") as! TableCell
22    
23            logCell.setValues(item: currentItem)
24    
25            return logCell
26        }
27    
28        override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
29            return 50
30        }
31    
32        override func viewDidLoad() {
33            super.viewDidLoad()
34            setupPusher()
35        }
36    }

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:

1func setupPusher(){
2        let options = PusherClientOptions(
3            host: .cluster("PUSHER_APP_CLUSTER")
4        )
5    
6        pusher = Pusher(
7            key: "PUSHER_APP_KEY",
8            options: options
9        )
10    
11        let channel = pusher.subscribe("log-channel")
12    
13        let _ = channel.bind(eventName: "log-event", callback: { (data: Any?) -> Void in
14            if let data = data as? [String : AnyObject] {
15                let logModel = LogModel()
16                logModel.logLevel = data["loglevel"] as? String
17                logModel.logMessage = data["message"] as? String
18                self.logMessageList.append(logModel)
19            }
20        })
21        pusher.connect()
22    }

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.

NOTE: Replace the placeholders with the credentials from your dashboard.

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

laravel-log-5-1

Conclusion

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.