6步集成ClassKit到你的应用中

1,022 阅读5分钟
原文链接: www.netguru.co
ClassKit was first introduced by Apple on the special educational keynote held in one of the Chicago’s schools in March 2018. The place of the event wasn’t something random - ClassKit enables developers to integrate their application with a brand new application called Schoolwork - an app for gathering and assigning students homework. Despite the fact that the target of the ClassKit framework is really small at the moment I think it’s a very good idea to integrate it as soon as possible if you have any type of educational app. As you will see from this blog post, doing so is very easy and you could contribute to making schools more innovative places!

Schoolwork App

The Schoolwork app lets you easily assign anything from worksheets to activities in educational apps, follow students’ progress, and collaborate with them in a real time. The app was presented on the March event however it couldn’t be downloaded by users till the end of the June. For a couple of months, it was only available for selected by Apple developers - you could ask for the access if you had some kind of educational app. Fortunately, it isn’t the thing anymore. Everyone can download it straight from the App Store and if you are a developer, downloading it adds very handy additional options inside device’s developer settings. Schoolwork users are divided into two kinds: teachers and students. Thanks to these additional settings you can easily switch between those groups so you don’t have to use separate devices and setup everything by yourself. Development version of Schoolwork app automatically creates fake classes with fake students for your convenience. Your app will be automatically available under the Schoolwork app if you prepare it correctly. Of course I will show you how to do this in next sections. There is one inconvenience however: You can’t test it in simulator because Schoolwork isn’t available in that environment. You have to use real device during the development and this device could be only iPad. Schoolwork app isn’t available for iPhones.

 

ClassKit

ClassKit is available for devices with iOS 11.4 or newer. Integrating it doesn’t replace any existing logic or storage mechanisms in your app, and you don’t use it to generate any new user interfaces. Instead, you use ClassKit to publicize the structure you already have. Every app that adopts ClassKit has a single, predefined top-level context called the main app context. Starting from this context you have to build a structure of separate child contexts that describe and fits your app best. After creating this structure of contexts you have to share them with the ClassKit DataStore. Thanks to this your app will be visible in the Schoolwork app and teachers will be able to use them to navigate to proper tasks inside your app. You should do this as early as possible, best if it is possible during the launch of the app however if your data lies on the remote server and it requires doing some kind of network request first, it still possible to integrate it with ClassKit. Just fetch the data on the startup and share it with ClassKit later.

 

Demo project

For purpose of this blog post, I’ve prepared a very simple application for testing student’s algebra skills. You can find it on my GitHub. There are two branches: master and without_class_kit. If you want to code when reading the blog post, switch to the without_class_kit one. I’ve already prepared // TODO comments for your convenience. Every TODO has a number that will match the number of step described here. If you just want to see complete working projects, use the master branch. There’s one class called GameService which will be responsible for all of the ClassKit integration. Here’s how the application looks in action: Jul-25-2018 19-59-26User can select the module and then the app shows him three questions. Each question has four answers. After answering all questions the users sees his score. That’s All. Let’s start integrating ClassKit to it! 

 

Step 1: Project settings setup

We have to start with enabling ClassKit inside the project’s Capabilities. After doing it head to the Apple Developer website and do the same thing there. To test the ClassKit, your developer membership must be active. Remember to regenerate your provisioning profiles after doing so.  You should be able to import and use the ClassKit framework now. 

 

Step 2: Create your context structure

// Create contexts
var contextsCoCreate: [String: CLSContext] = [:]
for module in modules {
    let context = CLSContext(type: .quiz, identifier: module.identifier, title: module.title)
    contextsCoCreate[context.identifier] = context
}

// Add contexts to parent only if they didn't exist before
let parent = CLSDataStore.shared.mainAppContext
let predicate = NSPredicate(format: "parent = %@", parent)
CLSDataStore.shared.contexts(matching: predicate) { (contexts, error) in
    contexts.forEach { contextsCoCreate.removeValue(forKey: $0.identifier) }
    contextsCoCreate.forEach { parent.addChildContext($0.value) }
    
    // Save our changes
    CLSDataStore.shared.save()
}
Swift

Inside method setupClassKitContexts() we have to prepare contexts matching the application logic and share it with CLSDataStore. These methods gets called at the launch time of the app. I’ve decided to put every module in a separate context with a type of quiz. These context gonna be siblings of the main app context - the teacher would be able to select the quiz exactly in the same way using Schoolwork app as we are doing it inside our app. Before adding new contexts we have to check if we haven’t done it already.

 

Step 3: Handle deep linking

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
    guard
        let contextPath = userActivity.contextIdentifierPath,
        let lastItem = contextPath.last,
        let module = gameService.modules.first(where: { $0.identifier == lastItem })
    else { return false }
    selectModuleViewController?.deepLink(to: module)
    return true
}
Swift

When the student launches the app from the Schoolwork app it should take him directly to the module that was selected by the user. We can do this using deep linking. ClassKit shares selected context path using NSUserActivity property called contextIdentifierPath. It’s an array of Strings pointing exactly to the context that was selected by a teacher. Our app didn’t have nested context so I’ve just used the last id to map an appropriate module. 

 

Step 4: Inform ClassKit that student started the module

func didStart(module: Module) {
    // Start ClassKit Activity
    CLSDataStore.shared.mainAppContext.descendant(matchingIdentifierPath: [module.identifier]) { context, error in
        guard let context = context else { return }
        context.becomeActive()
        self.currentActivity = context.createNewActivity()
        self.currentActivity?.start()
    }
}
Swift

A teacher should be able to track the time that elapsed during work on the quiz. We don’t have to calculate it by ourselves, ClassKit handles it for us. The only thing we have to is to create a new activity and call start() method when the student starts the module. Also, we have to keep the reference to this activity because it will be useful in the next steps. 

 

Step 5: Add additional activity items

[...]
let item = CLSBinaryItem(identifier: lastAnswered.identifier, title: lastAnswered.question, type: .trueFalse)
if case ExerciseState.answered(correct: true) = lastAnswered.state {
    item.value = true
} else {
    item.value = false
}
currentActivity.addAdditionalActivityItem(item)
Swift

Besides the final score that we will provide to the ClassKit at the end, we can provide additional activity items. It allows the teacher to see which questions were answered correctly and which were not. There are many types of the activity items so I encourage you to explore the documentation regarding CLSActivityItem and pick the one that will fit best to your app. For this kind of question, I’ve decided to go with CLSBinaryItem with a type of question  trueFalse. Don’t forget to add this item to the activity we’ve created in the previous step. 

 

Step 6: Publish score and stop the activity

func didFinish(module: Module) {
    // Finish activity and publish score to ClassKit
    guard let currentActivity = currentActivity else { return }
    let score = CLSScoreItem(
        identifier: module.identifier + "_score",
        title: "Total score",
        score: module.calculateNumberOfCorrectAnswers(),
        maxScore: Double(module.exercises.count)
    )
    currentActivity.primaryActivityItem = score
    currentActivity.stop()
    CLSDataStore.shared.save { _ in
        self.currentActivity = nil
    }
}
Swift

The user has answered all of the questions we had so we have to share the score with the ClassKit. We are using the CLSActivityItem for this again, however, this time we are setting it as the primary activity item. We don’t have to calculate the score by ourselves, again ClassKit will handle that for us - we just have to select most appropriate activity item. I’ve chosen CLSScoreItem for my use case. We can now call stop() method on the activity to stop the timer and save the ClassKit Data Store. That’s all. Our app is integrated with the ClassKit and we can test it on real device. 

 

Final result

Go to the settings, select teacher mode under developer ClassKit settings and inside Schoolwork app you should be able to create a handout with one of the modules we’ve shared with the ClassKit at the beginning. Now head again to the settings and switch to the student role. After running the Schoolwork app you should see that there’s a handout assigned to you and after tapping the application icon it will take you straight to the module using deep linking. After answering all questions your score will be visible inside the Schoolwork app, the same will see the teacher.Jul-25-2018 21-08-46

 

Conclusion

As you could see adopting the ClassKit is very easy and straightforward. ClassKit API is very well documented and easy to understand. If you want to learn more about it, Apple prepared very nice landing page  for the framework with all links to the documentation you should see if you want to play with it. I really recommend watching the WWDC 2018 session also. If you have any questions, just write a comment or mention me on Twitter (@kwiecien_co)

Link to the repository: GitHub