Streaming is available in most browsers,
and in the Developer app.
-
Meet ClassKit for file-based apps
The ClassKit framework can help surface educational activities within your app to teachers using the Schoolwork app. Discover how you can provide teachers with greater insights into student learning by adopting the latest file-based API to report student progress data within your app. We'll also show you how to use ClassKit to report out different data types, and how to test your implementation in developer mode.
Resources
-
Download
♪ Bass music playing ♪ ♪ Marin Eubanks: Hi, everyone.
I’m Marin, an engineer on the ClassKit team, and I’m excited to show you a new API we’ve added to ClassKit for file-based apps.
Today, I’ll go over Schoolwork and how it’s used with ClassKit.
Then, I’ll do an in-depth review of the new API for file-based apps.
Next, I’ll walk you through a sample implementation.
And finally, I’ll show you how to test the new API using ClassKit’s developer mode.
Let me start by giving you a brief overview of Schoolwork.
Schoolwork is an educational app that enables teachers to share assignments in which students use your apps to learn.
When your app adopts the ClassKit framework and advertises assignable content -- known as CLSContexts -- as well as starts reporting progress data on activities, teachers will be able to assign that content and view the progress data reported by your app.
If your app is ClassKit-enabled, teachers will be more likely to use your app in their curriculum.
And coming soon, Schoolwork will be even easier to use and adds many new features to streamline teacher workflows, inform instruction, and provide data from your apps to teachers.
Now that we’re familiar with Schoolwork, let’s see how the data from your app flows into Schoolwork.
Your app submits data to the ClassKit framework.
ClassKit surfaces that data to the Schoolwork app.
The data is then presented to the student and teacher.
Here is a view of Schoolwork with a few assignments of ClassKit-enabled apps.
If we tap on one of the assignments, we can see an example of an app which has adopted ClassKit and reported student-progress data.
We will go through the details of this use case a bit later.
Now that we have reviewed Schoolwork, let’s talk about our new file-based progress API.
There are more than 190,000 education apps in the App Store.
And while a lot of you have adopted ClassKit’s context-based APIs, not all of you have.
We received feedback specifically around apps that interact with files and how you wanted to adopt ClassKit but contexts didn’t quite fit your use case.
Well, if you’ve been holding out on ClassKit adoption because your app is file-based, we added a new API just for you.
This new API is for any app that interacts with files.
If you have an app that can edit files or just open and view a file, then you’ll love our new API for file-based apps.
Adopting this new API enables reporting student progress data on the files used within your app when they are assigned in Schoolwork.
When a teacher assigns content from a ClassKit-enabled app, they will be provided additional insights, which is a win for them and a great new use case for your app.
One important thing to note is that your app must adopt Open in Place.
When your app supports Open in Place, the exact file shared between the student and teacher will open in your app and not a copy.
Here's the new API for adding progress data to a file.
It’s called fetchActivity, and it lives on CLSDataStore.
I have both the async and async alternative versions of this API shown here.
You’ll pass in the file URL of your file to this API, and it returns a CLSActivity.
Once you have the CLSActivity, you can add progress data to it.
Now, let’s take a look at the types of progress data your app can submit.
If you’ve already adopted ClassKit, then this will be a review of the current progress data types we have available.
If you’re new to ClassKit, these classes are currently being used on CLSContexts, but the same data types can also be applied to files.
Here we have a CLSActivity.
This is a class used to encapsulate all of the progress data associated with a particular file.
We have a few types of data that can be added to a CLSActivity.
First we have duration.
This is the amount of time a student spent working the assigned file.
Time should be reported on all file types.
To use this API, you simply call the start and stop methods that live on CLSActivity.
Next we have progress.
This is some value between zero and one.
Progress is typically used when you can determine a student's progression through a file.
For example, let’s say you have an audio or a video file, and the student got 50 percent of the way through.
You would report the playback progress as .5.
To add progress, you can either set the progress property directly or add a range from some start to an end.
You can add overlapping ranges or the same range multiple times.
We’ll handle the logic to make sure the correct progress is reported to students and teachers.
We also have the primaryActivityItem which is useful if you have a file that can be edited.
Setting the primaryActivityItem indicates that, this piece of data, you want to highlight to students and teachers, and it shows up in the main part of the UI in the Schoolwork app.
There's also an additionalActivityItems property.
This is an array of CLSActivityItems which is useful for adding additional metadata.
To add a primaryActivityItem, set the primaryActivityItem property on CLSActivity.
To add an additionalActivityItem, call the addAdditionalActivityItem function on CLSActivity and pass in the activityItem you want to add.
The primaryActivityItem and additionalActivityItem properties hold a reference to one of our three subclasses of CLSActivityItem.
You can add any of the following subclasses: First, we have CLSBinaryItem.
This is used to represent any binary data type.
An example usage of this might be a question on a quiz.
Let's say the student got it correct or incorrect.
Or you can add CLSQuantityItem.
This is used for any generic numerical value.
You could use this for the number of pages, number of slides, or total word count on a document.
And the last is CLSScoreItem.
This class is used for anything that be represented as a part out of a total.
For example, a score on a quiz; the user got eight out of ten.
You can add any combination of these subclasses to an activity, one of them, or all of them.
Now that we know the types of data that we can add, let’s walk through a code sample of adopting this API into an app.
Here I have a sample app that can open and edit a text file.
When the student opens the text file, I'll start the timer.
The student will go through, edit the file.
When the student is about to close the file, I’ll record the total word count and stop the timer.
Let’s navigate to the part of my code that gets called when I open the file and the student starts interacting with it.
I have an openFile function.
This is where I will start tracking time.
In your app, you’ll go to the part of the code that you already have for opening a file, and this is where you’ll add a little bit of code to start the timer.
First, I’ll fetch the CLS activity for my file URL.
Once I have the activity, I will call start to start tracking time and then I will call save on CLSDataStore to commit the changes I’ve made.
Let’s go ahead and add a breakpoint here that we’ll come back to later when testing our implementation.
Now, I also want to stop the timer when the student is done and add a primaryActivityItem.
So let’s navigate to the part of my code that gets called when the student is about to close the file.
Here I’ll call CLSDataStore.shared. fetchActivity, grab the primaryActivityItem to update it if it already exists, or create a new CLSQuantityItem if there wasn’t already one.
Once I have the CLSQuantityItem, I can update its value and set it as the primaryActivityItem on my activity.
I can add progress to my activity.
And last, call stop to stop the timer.
Then, I make sure to call save.
If we don’t call save on CLSDataStore, then we will not persist any of the changes we just made.
I’m going to add a breakpoint here as well.
We’ll use this to help us debug our submission of student progress data.
Now that we’ve adopted the API into our sample app, let’s see how we can test our implementation using Schoolwork and developer mode.
First, we need to set the ClassKit environment entitlement to development.
This is inside of Xcode.
The default value is production.
We’ll change the value of the entitlement to development so that we can test using developer mode and Schoolwork.
The next time we run our code, it will run in developer mode.
It’s important to make sure to set this back to production after you're done testing.
Next, we need to turn on developer mode on our iPad.
We'll open the Settings app, navigate to Developer > ClassKit API.
We’ll select Teacher to change our role to a teacher in Schoolwork.
Now, we will we open the Schoolwork app.
When Schoolwork opens, we are presented with the teacher UI.
And if we tap on the Create Assignment button in the top right-hand corner, we can create an assignment adding a file our app supports by tapping the Files button.
Then we will select the file that we want to add, enter the class and the title of the assignment.
You can also optionally add any instructional text if you’d like.
And then tap the button in the top right-hand corner to publish this assignment to the class.
Now that we've created the assignment, we can switch our role to act as a student and test our implementation of submitting progress data.
So let's navigate back to the Settings app.
In Settings, we’ll select Developer > ClassKit API, and tap on Student.
This has now changed my role in Schoolwork to act as a student.
We'll go back to the Schoolwork app.
I can see I am now logged in as a student because I no longer have the Create Assignment button in the top right-hand corner of my UI.
In the middle of the screen, I see the assignment we just created, and if I tap on it, I am shown the details of the assignment.
I can tap on the file icon, and that will deep-link me into my app where I start reporting progress data.
The file opens up in my app, and my code gets called to start the timer.
Here we can see our breakpoint get hit after calling save to start the timer.
And if we hit Play and then go back to our app, I see the Student Progress banner drop down from the top, which is an indication that the save was successful and the timer was started.
Then I'll go through, add a bunch of text to complete the essay.
My sample app has a Done button the student will tap when they are done editing the file.
So I’ll tap that Done button in the top left-hand corner.
At this point, my closeFile function will get called.
We can see our second breakpoint was hit for saving the wordCount as the primaryActivityItem and stopping the timer.
Then, we can hit Play and go back to Schoolwork.
In Schoolwork, I can see the progress data submitted by my app.
First, I see the time as 41 minutes.
This validates that I'm calling start, stop, and save correctly.
Next, I see the word count, which I set as the primaryActivityItem.
Any CLSActivityItem subclass I set as the primaryActivityItem will show up here in the main part of the UI.
The fact that I can see my word count as 558 words validates that my submission of CLSQuantityItem is working correctly.
Now, let’s switch our role back to a teacher and see how the data submitted by my app appears to teachers.
In the center of the screen, we see I have the average time and average word count for all students.
Below that is a row for every student on the assignment.
In the Student cell, I see the data that one student submitted.
And if I tap on the Student cell, I can see the progress data reported by my app.
We have the primaryActivityItem, time, and one additionalActivityItem which is listed as Readability Grade Level.
And that is how you use developer mode to test your ClassKit integration.
Don’t forget to set the entitlement back to production.
Well, great! We covered a lot today, from the new API to testing it with developer mode.
Even if you don’t consider your app for education, there’s a good chance an educator does, and having it ClassKit-enabled means your app will be ready for them to integrate right into their curriculum.
So make sure to adopt our API.
And thank you.
Thank you for the feedback reports, and please submit any other feedback that you may have.
We love hearing from you.
And if you are interested in learning more about our context-based APIs, take a look at our previous sessions on "What’s new in ClassKit" and our talk "Introducing ClassKit" from 2018.
Thanks, and have a great WWDC! ♪
-
-
7:25 - openFile()
func openFile() async throws { // Your existing code for opening a file goes here. let activity = await try CLSDataStore.shared.fetchActivity(for: fileURL) activity.start() await try CLSDataStore.shared.save() }
-
8:07 - closeFile()
func closeFile() async throws { let activity = await try CLSDataStore.shared.fetchActivity(for: fileURL) let wordCount = activity.primaryActivityItem as? CLSQuantityItem ?? CLSQuantityItem(identifier: "total_word_count", title: "Word Count") wordCount.quantity = currentDocumentWordCount() activity.primaryActivityItem = wordCount activity.progress = progress() activity.stop() await try CLSDataStore.shared.save() }
-
8:48 - closeFile()2
func closeFile() async throws { let activity = await try CLSDataStore.shared.fetchActivity(for: fileURL) let wordCount = activity.primaryActivityItem as? CLSQuantityItem ?? CLSQuantityItem(identifier: "total_word_count", title: "Word Count") wordCount.quantity = currentDocumentWordCount() activity.primaryActivityItem = wordCount activity.progress = progress() activity.stop() await try CLSDataStore.shared.save() }
-
11:20 - openFile() BreakPointHit
func openFile() async throws { // Your existing code for opening a file goes here. let activity = await try CLSDataStore.shared.fetchActivity(for: fileURL) activity.start() await try CLSDataStore.shared.save() }
-
11:55 - closeFile() BreakPointhit
func closeFile() async throws { let activity = await try CLSDataStore.shared.fetchActivity(for: fileURL) let wordCount = activity.primaryActivityItem as? CLSQuantityItem ?? CLSQuantityItem(identifier: "total_word_count", title: "Word Count") wordCount.quantity = currentDocumentWordCount() activity.primaryActivityItem = wordCount activity.progress = progress() activity.stop() await try CLSDataStore.shared.save() }
-
-
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.