A journey towards Apple’s Exposure Notification Framework and how to use it
By: Mahmoud Eldesouky
Tags: Apple, Contact Tracing, Exposure Notification, Covid 19, Swift

Now let’s go through the Exposure Notification Framework and how to use it.

Framework Overview:

The concept of the Exposure Notification Framework depends on Bluetooth technology. It could be easily explained in three parts:

A. Contact Tracing: The Framework continuously broadcasts a privacy-preserving key identifier that changes every 10–20 minutes.

On the other hand, it also scans for other broadcasting identifiers. When a broadcasted identifier is detected, it will be recorded and securely store on the device.

B. Report Infection: When a user reports in the hosting app that he is infected, the app is expected to fetch from the framework a list of all the identifiers that have been recently used by that device, and upload it to the server.

C. Exposure Detection: Parallel to that, the hosting app is expected to periodically fetch from the server the list of key identifiers that were used and upload by infected users to the server. The framework then checks the device’s identifiers list against the downloaded list of infected identifiers. If there is a collision match, the user might be notified based on some configured parameters.

Framework Usage:

Perquisites: Xcode 11.5+, iOS 13.5+

Starting with the limitations, the framework requires the special entitlement “com.developer.exposure-notification” to work. And as announced by Apple, that this entitlement will be available for governments and public health authorities only. So far this limitation is even required in the debug environment as well. As the framework is still in beta, it is unclear if this will continue to be the case.

So far without an entitlement, your ways to get around it are either using a jailbroken device or another great workaround which is a mock framework done by Quentin Zervaas called TracePrivately to simulate Apple’s access limited framework. Thanks to his efforts, initial testings are possible without extra hacks. Of course, the mock framework is based on assumptions and is not doing the actual exposure scoring that is done by Apple’s framework, but sufficient for testing.

As explained earlier in the overview section, first thing the host app is expected to do is to start advertising its identifiers and monitoring the surrounding identifiers in its medium.

Hence, comes the first part. Contact Tracing! (aka. Exposure Notification)

A. Contact Tracing: To start the framework’s contact tracing feature, the host app is expected to call the following API:

Calling this API will handle:

Continuously broadcasting and scanning for random identifiers that aren’t tied to a user’s identity and that change every 10–20 minutes for protection. Check this document for more details about the rolling key identifiers. Securely present scanned identifiers and the contact essential details.

To call this API, the code will look something like:

Contact Tracing Snippet

Initialize an instance of ENManager . This will be one of our two interfaces to the framework. The second interface is ENExposureDetectionSession and will be explained in the third part. Activate the instance using activate(completionHandler: @escaping ENErrorHandler() API. This method must be first called and the handler must complete successfully before using the ENManager instance. Only then the features of the class can be used. Check for activation errors before using the ENManager instance. Now the ENManager instance is successfully activated, we request enabling the contact tracing feature using setExposureNotificationEnabled(_ enabled: Bool, completionHandler: @escaping ENErrorHandler) API. Calling this API triggers a system alert for authorization. Check for exposure notification enabling errors. In this case, the app could decide to terminate the activated ENManager instance using invalidate() API until errors are resolved. This API is also called when the app is done with its ENManager instance. To use the ENManager again, create and activate a new instance of the class. If no exposure notification enabling errors, then exposure notification is successfully enabled.

Screenshot of enabling exposure detection system alert.

Now comes the second part of the framework. Reporting Infection!

B. Report Infection: When the user reports that he is COVID-19 positive in the host app, the app should request fetching a list of all the identifiers that have been recently used by that device, and upload it to its server. Fetching the list of device identifiers is using the API:

This instance method as all other ENManager methods needs an initialized and active instance of ENManager to be called on. In the following snippet, we will assume that we are using the same initialized and active enManager instance created in Contact Tracing code snippet.

To call this API, the code will look something like:

Request fetching the list of most recent key identifiers used by the infected user’s device. On completion, ENGetDiagnosisKeysHandler is passed, containing potential Error? and [ENTemporaryExposureKey]? are retuned. Each time this API is called, a system alert is triggered for the user’s permission. Check for potential errors. After checking that a list of key identifiers is passed, send this list to your server to be stored. This list should be then fetched by other users to processed on their device to check potential exposures with infected users.

Screenshot by Guilherme Rambo of system alert when requesting DignosesKeys

Apple expects that the host app will somehow handle verifying the reported infections with its corresponding authorities as that the mechanism of official verification would vary from one public health authority to another.

Last but not least, Exposure Detection!

C. Exposure Detection: For the framework to check for any exposure possibilities, the host will have to create an ENExposureDetectionSession . ENExposureDetectionSession is the framework’s interface for this feature. The app must first download the list of infected key identifiers that are uploaded by other infected users. As that is out of scope, we will assume that we already have this list of infected key identifiers infectedKeyIdentifiers .

As that this list could grow large, the framework expects to be passed this list in form of batches, using API:

The batch sizes shouldn’t be greater than the maximumKeyCount defined under ENExposureDetectionSession . The second batch shouldn’t be passed except when the first completes successfully. Keep repeating this step until all keys are passed to the framework or an error occurs. When all keys are passed, the host app is expected to call:

On successful completion, a potential ENExposureDetectionSummary? object is passed in the ENExposureDetectionFinishCompletion handler. This object will contain a summarised overview of any exposures detected. For more detailed exposure info, use:

Where maximumCount is the maximum number of detected exposures the app is ready to handle in a single call. On completion, ENGetExposureInfoCompletion is passed containing a list of ENExposureInfo and a boolean done . That boolean represents if there are more exposures to be fetched or not. To fetch all exposures, repeat this step till the done value is true or an error occurs.

To achieve this, the code will look something like:

Initialize an instance of ENExposureDetectionSession . Same as ENManager instance, ENExposureDetectionSession must first be activated and completed successfully in order for its services to be used. Activate the instance using activate(completionHandler: @escaping ENErrorHandler() API. Check for activation errors before using the ENExposureDetectionSession . Use a recursive method taken and modified from this gist, to recursively batch and pass the infectedKeyIdentifiers list that is fetched earlier from the server. Pass a batch of infectedKeyIdentifiers that is not greater than the maximumKeyCount defined under ENExposureDetectionSession . Recursively repeat the process until all infectedKeyIdentifiers are passed. Check for error while batching the keys. Same as with the ENManager , you can decide to terminate the activated session using invalidate() . You also use this method when the app is done with its session. When all keys are added and batchPositiveDiagnosisKeys() completes successfully, call finishedDiagnosisKeys() API. This will process all passed infectedKeyIdentifiers and returns ENExposureDetectionFinishCompletion on completion. Check for any matches with infectedKeyIdentifiers , expressing exposure with other infected users. In case of exposure, the app could request more details about those exposures using getExposureInfo(withMaximumCount maximumCount: Int, completionHandler: @escaping ENGetExposureInfoCompletion) . Pass the maximum number of exposure infos the app could handle in a single call. Per the documentation, Apple recommends using a reasonable number as 100. After checking for possible errors, now exposuresList contains a batch of maximum 100 exposure infos. Optional fetch more exposure infos, till the done flag is true . A recursive technique like in batchPositiveDiagnosisKeys() could be used. Call invalidate() when the app is done with the session.

To prevent abuse, the framework enforces a limit on the rate that your app can use exposure detection session operations.

The host app can always configure the criteria to estimate risk using ENExposureConfiguration . More illustrations found in the sample app documentation.

The host app is expected to periodically check for exposure in a nonabusive mater. The best way of doing that is BGTaskScheduler . Because as per sample app documentation, when declaring a background task in the app’s Info.plist, the app should declare the task identifier ending with exposure-notification . The BackgroundTask framework detects apps that contain this special Exposure Notification entitlement prefix and the operating system will guarantee to launch these apps automatically when they aren’t running and allow them more background time to ensure that the app can process and report results promptly.

The documentation sample app has a great example of doing that in a more optimized way using DispatchGroup .

Further Guidelines mention by apple in their sample app.

• Inform users that they can choose to enable Exposure Notifications, as well as that they can disable them at any time. • Explain that this only works with other devices that have Exposure Notifications turned on. • Explain the use of Random IDs, including what they are, how they’re shared and collected, and the privacy protections associated with them. • Explain how a user can be notified of an exposure event (including time), as well as the fact that exposure details (date, duration, and signal strength) will be shared with you. • Include an explanation of how a user may work with you to submit a positive diagnosis, with their consent.

Now we have a full overview about the Exposure Notification Framework.

Special thanks to community members like Quentin Zervaas for contributing with such efforts in a short while to provide his mock framework solution for the his community peers. I hope that article helped you in understanding the Exposure Notification Framework better. Thank you.

You can always reach me on:

• Twitter

• LinkedIn

• Email

References:

• Apple Docs • TracePrivately • Snippet • Framework Sample App