3️⃣Analytics

Spring 2024 | Vin Bui

Google Analytics is an app measurement solution that allows us to view our app’s usage and other insights. It allows us to understand how people use our applications through defining and tracking custom user events. It helps us understand the behavior of our users, allowing us to make informed product decisions and improving the user experience.

Getting Started

In order to set up Google Analytics, we must have a Firebase project configured for our app.

  1. Under Project Settings > General, download the GoogleService-Info.plist file and drag it into your project directory.

  2. Install the Firebase SDK via CocoaPods or Swift Package Manager and choose the libraries that you want to use (in this case FirebaseAnalytics).

  3. Follow the instructions from the Firebase website to add the initialization code.

Adding the SDK

The official Firebase documentation does a pretty good job explaining how to set up Google Analytics so I won’t repeat it here. Follow the guide to add the SDK.

Using the SDK

Our first step is to create a file that will manage our analytics. Let’s call this file AnalyticsManager.swift.

Creating Events

We can create custom events that can be triggered as a response to user interactions.

AnalyticsManager.swift
/// A structure that represents a Google Analytics event.
struct Event {

    /// The name of the event.
    let name: String

    /// The parameters to pass in to this event.
    let parameters: [String: Any]?

}

This is a general Event type that will be used by Analytics to log. Let’s make it more specific to our app. Let’s use Uplift in our example.

AnalyticsManager.swift
/// An enumeration representing an Uplift event.
enum UpliftEvent: String {

    /// Taps on a gym cell on the home page.
    case tapGymCell = "tap_gym_cell"

    /// An enumeration representing the type of event.
    enum EventType {
        case facility
        case gym
    }

    /**
     Retrieve an `Event` object for this custom event.

     Do not pass in any parameters to this function if no parameters are tracked for this event.

     - Parameters:
        - type: The type of the event to track used as the parameter key.
        - value: The value for the parameter key.

     - Returns: An `Event` to be tracked in Google Analytics.
     */
    func toEvent(type: EventType? = nil, value: String? = nil) -> Event {
        // No Parameters
        guard let type,
              let value else { return Event(name: rawValue, parameters: nil) }

        // With Parameters
        var parameters: [String: Any]
        switch type {
        case .facility:
            parameters = ["facilityName": value]
        case .gym:
            parameters = ["gymName": value]
        }
        return Event(name: rawValue, parameters: parameters)
    }

}
  1. Create an enum called UpliftEvent with a raw String type.

  2. Define custom events with a case statement. The raw value should be separated by underscores. In this example, we created an event that tracks the tapping of a gym cell.

  3. Create a nested enum called EventType. This enum will be used if we need to pass in parameters along with our events.

    1. In the event we defined above, since we are tracking a user’s interaction with a gym cell, it would be useful to know which gym they are selecting. We can pass in parameters that will contain this information (which is why we create a gym case in our EventType enum).

  4. Create a function that converts our UpliftEvent to the Event struct that we created earlier.

    1. We handle the case in which there are no parameters using a guard let statement and return just the raw value of the enum.

    2. If there are parameters, we can perform a switch statement to break down the event types to determine the key-value pair for the event parameters.

Logging Events

After defining all of our event types, we can then begin writing the actual AnalyticsManager.

AnalyticsManager.swift
/// Manage Google Analytics.
class AnalyticsManager {

    /// Shared singleton instance.
    static let shared = AnalyticsManager()

    private init() {}

    /// Log an event to Google Analytics.
    func log(_ event: Event) {
        #if !DEBUG
        Analytics.logEvent(event.name, parameters: event.parameters)
        #else
        Logger.statistics.info("[DEBUG] Logged event: \(event.name), params: \(event.parameters?.description ?? "nil")")
        #endif
    }

}
  1. Just like any other utils manager we create (such as NetworkManager), we create a shared singleton instance and make the initializer private.

  2. We then create a single function that takes in an Event type.

    1. The #if DEBUG statement is used to determine our app’s build setting. When working in a development environment, we do not want to be tracking analytics. Instead, we can print (or even better, log) the event in the development environment.

In our example, we can log the tapping of a gym cell with the following code:

// Assume `gym` is a `Gym` object with a `name` property...
AnalyticsManager.shared.log(
    UpliftEvent.tapGymCell.toEvent(type: .gym, value: gym.name)
)

Example Analytics

Last updated