Creating a Laravel Logger - Part 5: Creating our iOS application
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.
Requirements
To follow along with this series you need the following things:
- Completed previous parts of the series.
- Laravel installed on your local machine. Installation guide.
- Knowledge of PHP and the Laravel framework.
- Composer installed on your local machine. Installation guide.
- The latest version of Android Studio installed on your machine (If you are building for Android).
- Knowledge of Kotlin and the Android Studio IDE.
- The latest version of Xcode installed on your machine (If you are building for iOS).
- Knowledge of the Swift programming language and the Xcode IDE.
- A Pusher application. Create one here.
- A Pusher Beams application. Create one here.
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
use_frameworks!
pod 'PusherSwift'
pod 'PushNotifications'
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.
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
@UIApplicationMain
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)
pushNotifications.registerForRemoteNotifications()
try? self.pushNotifications.subscribe(interest: "log-interest")
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
pushNotifications.registerDeviceToken(deviceToken)
}
}
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 {
self.tableView.reloadData()
}
}
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() {
super.viewDidLoad()
setupPusher()
}
}
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
self.logMessageList.append(logModel)
}
})
pusher.connect()
}
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:
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.
28 March 2019
by Neo Ighodaro