Build a research and care app, part 3: Visualize progress
Learn how ResearchKit and CareKit can work together to take the tedium out of paper surveys. Join us for the last part of our code along as we put the finishing touches on our care pilot app. Explore how you can use advanced CareKit APIs to customize the appearance and behavior of task cards, find out how to plot answers to ResearchKit surveys in CareKit charts, and discover how you can use ResearchKit to present engaging educational content.
This is the final session in a three-part Code-Along series. To get the most out of this session, we recommend first watching parts one and two of “Build a research and care app.” And for more background on these frameworks, watch "ResearchKit and CareKit Reimagined” from WWDC19.
♪ Bass music playing ♪ ♪ Erik Hornberger: Welcome back to the third and final installment of our Research and Care app code-along! If you'd like to follow along, you can find the source code for this app in the session resources. Let's log in and get started. In our last session, we added a couple of tasks into the app. Since then, I've been getting all kinds of notifications from Jamie. I have a feeling that something's up. Let's see. Jamie will arrive at the clinic in 10 minutes. Jamie shared a Motivation Playlist. Wow! As you can see, the ever-enthusiastic Jamie is on his way to meet with the clinicians right now. It looks like Jamie has asked us to make a couple of changes and to add two new features. The first bit is about enhancing the surveys that we implemented in session two. Jamie says he got some feedback about them from testers. He told us the feedback that he got was that testers want to be able to tell what answers they gave after the fact. Right now, the card just shows that the survey has been completed, but if you scroll back in time a couple of days, there's no way to tell what answer you gave on that day. They'd also like us to restrict editing to the current date. You shouldn't really be able to delete survey answers or redo range of motion tests in the past. Similarly, it doesn't really make sense that you can scroll out into the future and preanswer surveys on days that haven't come yet. So we'll start off by addressing that feedback and enhancing the surveys a bit. We've also got this Insights tab that's still looking a bit lonely. Jamie asked that we display a pair of charts there. One will capture the relationship between sleep and pain, and the other will show improvement in range of motion over time. Finally, Jamie tells me that the doctors have asked we include some educational content to help participants understand what a torn meniscus is, and ResearchKit will be able to help us out there. We're going to begin by enhancing the surveys. Let's tackle showing the answers the patient gave. We'll go ahead and display the given answers as text in the card.
Now, in CareKit, tweaking the appearance of a task card is done by passing a viewSynchronizer into its initializer. Let's take a look at how we can create a custom View Synchronizer. We'll subclass the existing OCKSurveyTaskViewSynchronizer. This class has two methods that we can override: makeView and updateView. updateView will be called every time the data in the store changes, and it's where we can apply customizations to our view. We always start out by calling the superclass's implementation and apply our enhancements on top of that. We'll check to see if there is an event with a completed outcome. If there is, that means that the survey has been finished. We'll snag the pain answer and the sleep answer by referencing the kind property that we set back in part two. I mentioned that by setting the kind property, it would help us out later, and this is one of the applications that I was alluding to. Now that we have the answers handy, we can use string interpolation to insert the answers into our card's instruction label. And that'll take care of showing the answers. Jamie also asked that we disable editing of past tasks. One way we can do that is to first set ourselves as the delegate for our survey task cards and then fill in this delegate method: viewController for task shouldAllowDeleting OutcomeForEvent. Our job is to return a boolean that tells CareKit if it should allow a particular event's outcome to be deleted or not.
We'll look at the date that the event falls on. If the date is earlier than today, we'll say that it can't be deleted. If it is on or after today, we'll allow deleting it. And just like that, we've prevented deletion of past data. The third thing Jamie asked is that we also prevent participants from completing surveys on future dates. To do that, we'll climb up a bit higher in the same file to just before where we create our task view controllers, and we'll use some Calendar utilities to check if the day we're populating content for is in the future or not. If it is a future date, we'll disable interaction with the task card, and we'll reduce the opacity to visually indicate that it's disabled. All right, nice! Now we shouldn't be able to complete future tasks either. Let's see where we stand.
The first thing that you'll notice is that the answers that were given for surveys are now displayed in the survey task cards. We still have the option to delete or redo surveys on the current date, but if we swipe back into the past, we're no longer able to redo them. And if we jump forward into the future, we can preview what's coming up, but we can't complete any of the surveys yet. Our app is really coming together now! The last two things we need to do are the charts and educational content, and these are both in the Insights tab. We're going to start off with a two-series bar chart showing the pain rating and hours of sleep side by side. We'll need to create two OCKDataSeriesConfiguration objects. The first is for the pain series. The ID tells CareKit which task's data to plot on the chart. We'll also pass a legend title, colors, a marker size -- which determines how wide the bars will be -- and an event aggregator. The event aggregator is responsible for looking at all the events that occur on a given day to determine what Y value should be used on that day. For the check-in task, we know there will only ever be one event per day, so we can just take the first event and get the answer to the pain question. So that's the pain series configuration. We'll also need one for sleep. The sleep series is almost identical. We're plotting data from the exact same check-in task. The difference is that we display the sleep answer, instead of the pain answer. With both of these in hand, we can construct a chart view controller. We'll choose a bar chart and set the date to today. Of course, we also need to pass in our two series and a reference to the store manager, which is used to keep the chart up to date as the content of the store changes. Great, so that's our first chart. Let's make one more! This time, it's going to be a scatter chart for range of motion. We'll need to create a data series configuration just as we did before, but this time around, we'll only need one. The only difference this time is that we're plotting data from the range of motion task instead of check-in task, and we're using the range answer for the Y axis. Next, we'll create our view controller. This time it's going to be a scatter plot, and we only have one data series. And just like that, we've got both of our charts set up. Let's see how they look. Jumping over the Insights tab, we can see both of our charts are now rendering. They look really nice! If we jump back, and we add or delete some outcomes -- here, we'll delete both outcomes for Tuesday -- and then return to the Insights tab, we should see our charts updated automatically. And they have! There's no longer any data being shown for Tuesday. Nice! So charts are looking good. Jamie also asked that we give the participants an option to view a 3D model of the knee and the meniscus, along with some explanatory text he received from our clinical partners. ResearchKit can help us out with that. I'd like to pause for a second to note that this time around, we are not tying the ResearchKit survey to a CareKit schedule. There's no particular time at which we want participants to look at this content, so we don't need the notion of a schedule. Similarly, there aren't any results for us to persist into CareKit's store, so we don't need to create a CareKit task or use CareKit's survey task view controller. That said, we can use the FeaturedContent view that my teammate Gavi introduced at WWDC last year. We'll need to set ourselves as the delegate so that we can be told when the participant taps the featured content card. When they do, we'll create a kneeModelTask, wrap it in an ORKTaskViewController, and present it to the participant. When they're done viewing the model, we'll get a callback right here, and we can use that as an opportunity to dismiss the ResearchKit view controller and bring the participant back into the Insights tab. All right, very nice! But we are missing a definition here for this knee task. Let's go fill that in over in Surveys.swift. It's going to be just two steps, where the first is going to be an instruction step. I hope these are starting to feel at least a little bit familiar to you by now, since we used them several times already today. The second step is a 3D model step. Whenever we create a 3D model step, we also need to pass in a modelManager, so just up above it, we'll create a USDZ model manager to pass in. We're going to start off by displaying a toy robot just to make sure that everything is working. The last bit is to assemble an ordered task with both of our steps and to return it. Now, when we run our app, we'll see the featured content card in the Insights tab, and tapping on it will bring up our instruction step, followed by our toy robot model. We can interact with it by rotating, zooming in on it... pretty neat! If you'd like to know more about how the 3D model manager works, or how you can implement your own version of it, you can check out Pariece's WWDC session from last year. To finish up our app, I'm going to swap out our toy robot for BioDigital's model manager. We'll include some notes on this in the project's Read Me, in case you're interested in knowing the details. With this version of the model manager, we can provide educational text from the clinicians. Here you can see some content provided by our clinical partners. We can also highlight the meniscus for the participant's reference to help them understand more about their injury and what the path to recovery will be. Our app is really coming together now! Actually, that's it, that is everything! We have checked all of the boxes! And just in the nick of time, too! It looks like we're getting another call from Jamie. Hey Jamie, good timing! We just wrapped up everything that you asked us to do. Jamie: Oh wow, yeah. I'm taking a look at it right now, Erik. Let's see... Yeah, this is really coming along nicely. The rest of the team is going to be thrilled, and this is going to open up so many research opportunities! Quick question for you. Before I head into this next meeting, what should I tell the team to do if they have any questions for you? Erik: Hey, that's a good question! So ResearchKit and CareKit are both open source, and our team is active on GitHub. If they have any questions about the frameworks, if they want to request a new feature, or if they want to contribute, tell them to open a new issue on our GitHub repos. Jamie: OK yeah, that's fantastic. I'll pass that info along to the team. Erik: By the way Jamie, you should consider telling us more about your study! If you go to researchandcare.org, you'll find a link there that you can use to tell Apple the details about who your study helps. We love to hear about how our frameworks are being used by the community! We also have an Investigator Support Program that offers grants of Apple Watch to institutions that propose novel research studies. If they want to apply, they can find the details on our website as well. Jamie: Really? That's fantastic! I think they'll definitely want to take advantage of that. But, Erik, all right I've got to pop into another meeting. I've got tons of big ideas for a second app that I want to run by you later. How long do you think an app for Apple Watch would take? Erik: All right, but let's catch up and discuss that later; like, in a couple of days. I think I've got enough to keep me busy for a while! Jamie: Oh yeah, I heard you're doing a code-along this year for WWDC? Good luck with that! I'll talk to you later! Erik: If you'd like more info, you can find it on researchandcare.org. Source code is available on GitHub, and we have two other sessions this year that lead up to the one you just watched. Well, that's all we've got for you folks. Thank you for joining us for our code-along! We saw how our sibling frameworks, ResearchKit and CareKit, can be used in tandem to quickly iterate on an app. We also covered some of our new features and our latest best practices. I hope you were able to pick up a few tips and tricks along the way. From all of us here on the team, we hope that you have a great WWDC! ♪
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.