FitTrack: Building an iOS Fitness Tracker

Objective: The objective of this project is to develop a comprehensive iOS fitness tracking application called FitTrack. This app will allow users to track their daily activities, including steps, distance, calories burned, and active minutes. FitTrack will leverage the CoreMotion framework to access the device’s built-in sensors and collect motion data. The project will focus on utilizing iOS development skills, integrating fitness tracking features, and creating an intuitive user interface. By completing this project, you will gain a solid understanding of iOS development, specifically in the domain of fitness tracking, and learn how to build a user-friendly mobile application.

Learning Outcomes: By working on this project, you will:

  • Gain proficiency in iOS app development, including user interface design and data handling.
  • Learn how to integrate fitness tracking capabilities into a mobile application using the CoreMotion framework.
  • Develop skills in data visualization, displaying fitness data in a meaningful and visually appealing manner.
  • Understand the importance of user experience (UX) design and learn how to create an intuitive interface for a fitness tracking app.
  • Acquire knowledge of best practices for handling user permissions and data privacy in a mobile application.

Steps and Tasks: Step 1: Set Up Xcode Project and User Interface

  • Create a new Xcode project with a Single View App template.
  • Set the project name as “FitTrack” and ensure that the language is set to Swift.
  • Open the Main.storyboard file and design the user interface for the app.
  • Add labels, buttons, and other UI elements to display fitness data and interact with the app.
  • Use constraints to ensure that the UI elements are properly positioned and responsive.

Step 2: Request User Authorization for Fitness Tracking

  • Import the CoreMotion framework by adding import CoreMotion at the top of your ViewController.swift file.
  • Inside the viewDidLoad method of your ViewController class, create an instance of CMMotionActivityManager and CMPedometer.
  • Request user authorization for fitness tracking by calling the CMMotionActivityManager’s requestAuthorization method and the CMPedometer’s authorize method.
  • Handle the user’s authorization response in the completion handler of the requestAuthorization method.

Step 3: Implement Daily Step Count Tracking

  • Inside the completion handler for user authorization, check if the user has granted authorization.
  • If authorization is granted, create a new Date instance for the start time (e.g., let startDate = Calendar.current.startOfDay(for: Date())).
  • Use the CMPedometer’s queryPedometerData(from:to:withHandler:) method to retrieve the user’s step count data.
  • Display the user’s step count in the app’s UI.

Step 4: Visualize Daily Step Count Data

  • Install the Charts library using CocoaPods by adding pod 'Charts' to your Podfile and running pod install.
  • Import the Charts framework by adding import Charts at the top of your ViewController.swift file.
  • Create a new bar chart view in your storyboard and connect it to an outlet in your view controller.
  • Create a function to configure and update the bar chart with the user’s daily step count data.
  • Call this function after retrieving the user’s step count data and pass in the appropriate values.

Step 5: Track Distance and Calories Burned

  • Use the CMPedometer’s queryPedometerData(from:to:withHandler:) method to retrieve the user’s distance and calories burned data.
  • Display the user’s distance and calories burned in the app’s UI.

Step 6: Implement Real-Time Step Count Updates

  • Create a function called startUpdatingStepCount that takes a start date as a parameter.
  • Inside this function, use the CMPedometer’s startUpdates(from:withHandler:) method to start receiving real-time step count updates.
  • In the update handler, check if the CMPedometerData’s startDate is after the start date parameter, and if so, update the app’s UI with the new step count data.
  • Call this function with the current date when you want to start receiving real-time step count updates.

Step 7: Enhance the User Interface

  • Implement a visually appealing design for the app, using color schemes and icons that align with the concept of fitness tracking.
  • Consider adding animations or progress indicators to provide a more engaging user experience.
  • Organize the UI elements in a logical and intuitive manner, making it easy for users to understand and interact with the app.

Step 8: Test and Refine the Application

  • Run the app on a physical device or simulator to test its functionality.
  • Ensure that the app accurately tracks and displays the user’s daily steps, distance, and calories burned.
  • Test edge cases, such as when the user has not granted authorization or when the device does not support the required sensors.
  • Seek feedback from users and make any necessary refinements to improve the app’s usability and performance.

Evaluation: To evaluate your project, you can consider the following criteria:

  • The app correctly requests user authorization for fitness tracking and handles the user’s response.
  • It accurately tracks and displays the user’s daily steps, distance, and calories burned.
  • The data is visualized in a clear and meaningful way using charts or other visual elements.
  • The user interface is well-designed, intuitive, and responsive.
  • The app handles errors and edge cases gracefully, providing a smooth user experience.
  • User privacy and data security are prioritized, following best practices for handling user data.

Resources and Learning Materials:

Need a little extra help? Here are some code snippets to help you get started on your FitTrack project:

Requesting User Authorization for Fitness Tracking:

func requestAuthorization() {
    if CMMotionActivityManager.isActivityAvailable() {
        let activityManager = CMMotionActivityManager()
        activityManager.requestAuthorization { (status) in
            // Handle user's authorization status
            switch status {
            case .authorized:
                self.startTracking()
            case .denied, .restricted:
                print("Authorization denied or restricted.")
            case .notDetermined:
                print("Authorization not determined.")
            @unknown default:
                fatalError("Unknown authorization status.")
            }
        }
    } else {
        print("Activity tracking is not available.")
    }
}

func startTracking() {
    if CMPedometer.isStepCountingAvailable() {
        let pedometer = CMPedometer()
        pedometer.startUpdates(from: Date()) { (data, error) in
            // Handle step count updates
            if let stepCount = data?.numberOfSteps {
                print("Step count: \(stepCount)")
            }
        }
    } else {
        print("Step counting is not available.")
    }
}

Querying Step Count Data for a Specific Time Range:

func queryStepCountData(from startDate: Date, to endDate: Date) {
    let pedometer = CMPedometer()
    pedometer.queryPedometerData(from: startDate, to: endDate) { (data, error) in
        if let stepCount = data?.numberOfSteps {
            print("Step count: \(stepCount)")
        }
    }
}

Visualizing Step Count Data using Bar Charts:

import Charts

class ViewController: UIViewController {

    @IBOutlet weak var barChartView: BarChartView!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureBarChart()
        updateStepCountChart()
    }

    func configureBarChart() {
        barChartView.xAxis.valueFormatter = ChartXAxisFormatter()
        barChartView.xAxis.labelPosition = .bottom
        barChartView.xAxis.drawGridLinesEnabled = false
        barChartView.leftAxis.axisMinimum = 0
        barChartView.rightAxis.enabled = false
        barChartView.legend.enabled = false
    }

    func updateStepCountChart() {
        let startDate = Calendar.current.startOfDay(for: Date())
        let endDate = Date()

        queryStepCountData(from: startDate, to: endDate) { (stepCountData) in
            var dataEntries: [BarChartDataEntry] = []

            for i in 0..<stepCountData.count {
                let dataEntry = BarChartDataEntry(x: Double(i), y: Double(stepCountData[i]))
                dataEntries.append(dataEntry)
            }

            let chartDataSet = BarChartDataSet(entries: dataEntries, label: "Step Count")
            let chartData = BarChartData(dataSet: chartDataSet)

            DispatchQueue.main.async {
                self.barChartView.data = chartData
            }
        }
    }
}

class ChartXAxisFormatter: NSObject, IAxisValueFormatter {

    let dateFormatter = DateFormatter()

    override init() {
        super.init()
        dateFormatter.dateFormat = "MM/dd"
    }

    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        let date = Calendar.current.date(byAdding: .day, value: Int(value), to: startDate)!
        return dateFormatter.string(from: date)
    }
}

Remember, these snippets are just a starting point, and you should continue to explore and expand your FitTrack app by implementing additional features, refining the user interface, and handling errors and edge cases. Good luck, and have fun building your iOS fitness tracker!

@joy.b has been assigned as the mentor. View code along.