Building a COVID-19 symptom tracker in CareKit: Part 1

Source: CareKit by carekit-apple (BSD)

Introduction

CareKit is a powerful OpenSource framework which provides a lot of functionality out of the box to help us build applications to help guide users through Care plans.

In order to get to grips with the CareKit framework and how to use it, we will build a simple application which allows a user to locally track some symptoms of COVID-19. This simple application is for demonstration purposes only and merely serves as a premise for us to explore the CareKit framework. Please use the official symptom tracker recommended for your country.

We will start off small, for this first tutorial the application we build will allow a user to track coughing episodes each day.

Fig 1.0 A simple CareKit application which allows users to track episodes of prolonged coughing all throughout the day.

Integrating CareKit

In order to get started we our going to create a new Xcode project and select a SingleView application as our kicking off point.

Fig 2.0 Creating a Single View application in Xcode.

In Xcode 11 integrating CareKit really couldn’t be simpler. CareKit itself is open source and available through Swift Package Manager. This means we can integrate the dependency directly through Xcode, by clicking File -> Swift Packages -> Add Package Dependency. The url for the dependency is

https://github.com/carekit-apple/CareKit

At the time of writing it is recommended to point directly at the master branch.

Using Swift Package manager to integrate CareKit
Fig 2.1 Integrating CareKit using Swift Package Manager

For this tutorial we will only import the top level CareKit package. This package depends on CareKitUI and CareKitStore so we will still have access to everything we need to build a CareKit project.

Creating a daily view

While not a requirement, CareKit is definitely built around the OCKDailyPageViewController. This class provides a lot for us, it creates a scrollable calendar with completion rings and a nice API for creating tasks for our user to complete.

To get started we will create a subclass of OCKDailyPageViewController:

This subclass will serve as our application landing page. It is worth noting at this point that init(fromCoder:) has not been implemented for OCKDailyPageViewController and will crash the application if called. This is because OCKDailyPageViewController must be initialised with a OCKSynchronizedStoreManager, which itself must be initalised with a OCKAnyStoreProtocol.

There is a lot going on here so lets break it down:

  • OCKAnyStoreProtocol: A protocol describing a type which CareKit can use to read and write care plans and patients progress. We could write a custom implementation of this which connects the app to a remote server. For this tutorial we will use the built in OCKStore which is an OCKAnyStoreProtocol compliant wrapper around CoreData.
  • OCKSynchronizedStoreManager: This object basically wraps the OCKAnyStoreProtocol’s five separate delegates into a Combine friendly API (using publishers).
  • OCKDailyPageViewController: This is our main view controller. Behind the scene it uses Combine to help reflect changes across the application. For example completing a task will automatically update a users progress rings without us as developers having to write any code.

This can still be a lot to take in so it is definitely worth exploring the implementations of the above (which we can because CareKit is open source).

To make life easier we are going to set our project to NOT use a storyboard and instantiate our view controllers automatically. We can do this by deleting the storyboard (and the automatically generated ViewController.swift file) and removing the reference to it in our Info.plist (Application Scene Manifest > Scene Configuration > Application Session Role > Item 0 > Storyboard).

To make life simpler for ourselves and to save us from having to query UIApplication.shared as? AppDelegate in lots of places we will create a singleton object that wraps our instance of OCKSynchronizedStoreManager.

While singletons are generally frowned upon, in this case the object only needs to exist once and for the entire lifecycle of the application. So for the purposes of this demo I feel comfortable in recommending something like:

Those familiar with setting up a CoreData stack will recognise the method used here. We lazily create a store with a unique name (as our application could have more than one store). The main difference here is we wrap it in our OCKSynchronizedStoreManager .

Now we can instantiate our SymptomTrackerViewController and get something on screen! If we head to our SceneDelegate and replace the autogenerated code with the following:

Note we added a little styling by adjusting the tint colour of the window. If we build and run our application we should see something like this:

Fig 3.0 CareKit daily view displayed on screen. Note that in this example we have given the view controller a title in viewDidLoad

The app, while still very plain is starting to take shape. We can navigate through different days, see our inactive completion rings (as we have no tasks) and navigate to the current day with the left bar button item.

Tracking coughing episodes

The first task we are going to create for our users is one that allows them to log any coughing episodes. According to nhs.uk any more than three coughing episodes in 24 hours is a potential symptom of COVID-19.

First things first we will add a TaskIdentifier enum to our CareStoreReferenceManager . This will contain a unique identifier for every kind of task we want a user to perform.

Next we will, for the purposes of our demo, create an extension on OCKStore to populate it with our daily tasks.

The above code is actually rather simple in essence we create a schedule for our task, then we create a task passing in the schedule at which it should be performed and add the task to our store.

We now need to call populateDailyTasks() when we create our store in our CareStoreReferenceManager

This will create our task but we still need to display it. Head over to SymptomTrackerViewController and add the dailyPageViewController(_:prepare:for:) function:

The above function is called when the daily page view controller loads a date. This happens on the initial page load and when you navigate to a new date on the calendar. When this happens we take the following steps:

  1. Create a query for the date to be displayed for every known type of task.
  2. Execute the query and handle the results
  3. For each task returned we check it’s identifier so we can decide how to handle it
  4. For our coughingEpisodes task we will display it using some built in CareKitUI OCKButtonLogTaskViewController which creates a card like view
  5. We append the card to the instance of OCKListViewController passed into the function.

Now if we build and run our application we should see our card displayed and we can interact with it.

Fig 4.0 CareKit daily view now allows user to track coughing episodes each day.

One thing to note here is that logging a coughing episode affects the users completion rings. It will say a user has not completed their daily tasks if they do not log a coughing episode. While this is useful functionality that we will dive into in further tutorials it does not make sense for this use case. We can fix this by setting the impactsAdherence property of our coughingEpisode task to false. This means this task will be ignored for calculating whether or not a user has completed their daily tasks.

Summary

In this tutorial we have created a new project, integrated CareKit and built the skeleton of our CareKit application. We have a daily view, we have covered creating tasks and scheduling, as well as rendering a default component. We still have lots to cover though.

In the next part of this tutorial we will look at creating a custom card to allow the user to log their temperature every day.

If you would like to see the source code for this application as it stands at the end of this tutorial it is open sourced under this tag.

--

--

At Kin + Carta, we're busy building technology experiences for a world where mobile is an expectation, not a device. ‘Kin + Carta Created’ is where we share selected learnings and highlights. Head to www.kinandcarta.com for more.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store