BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Apple Releases iOS 13.5 with Exposure Notification Beta and Best Practices Sample App

Apple Releases iOS 13.5 with Exposure Notification Beta and Best Practices Sample App

This item in japanese

Bookmarks

The latest release of iOS, iOS 13.5, includes beta support for the Exposure Notification API that Apple defined jointly with Google to enable contact tracing apps. Apple also published a sample app to showcase best practices in contact-tracing apps.

Besides providing the actual framework implementation, iOS 13.5 includes the basic user-facing authorization mechanism that lets users opt in to or out of contact logging. No apps using the Exposure Notification API are available yet, which means that the Exposure Logging setting will be disabled by default. When you install a third-party app developed by some public health authority, users will be given the option to opt in or out.

To make things easier for third-parties wanting to build a contact tracing app, Apple has published a sample app providing a reference design. In addition to showing best practices when using the framework, the sample also includes code to simulate central server responses to implement diagnosis key sharing and exposure criteria management.

The Apple sample app checks on launch whether the user has enabled exposure logging, and asks them to enable it in the case that they did not. Contrary to what usually happens with other privileges managed by iOS, the Exposure Notification API provides a mechanism for the app to explicitly trigger the authorization mechanism through the ENManager singleton:

static func enableExposureNotifications(from viewController: UIViewController) {
    ExposureManager.shared.manager.setExposureNotificationEnabled(true) { error in
        NotificationCenter.default.post(name: ExposureManager.authorizationStatusChangeNotification, object: nil)
        if let error = error as? ENError, error.code == .notAuthorized {
            viewController.show(RecommendExposureNotificationsSettingsViewController.make(), sender: nil)
        } else if let error = error {
//...
        }
    }
}

Apple's sample goes as far as asking the user to enable the service twice, if they deny their permission on the first request. This is obviously not a requirement but hints at Apple considering this an accepted practice, which could mean such an aggressive strategy to gather user permission will not be considered cause for rejection in the eventual App Store review process.

The app stores all data it logs locally, including a flag telling whether the user on-boarded or not, data about any test they took, whether they shared it with the server, etc. Not requiring to store all user data on a central server is a key feature of the Exposure Notification protocol, since storing it locally preserves user pricacy.

Only when a user is positively diagnosed COVID-19, they may decide to share it with the central server. This requires the app to retrieve a list of diagnosis keys, which in turns requires the user to provide an explicit authorization each time, and send it to the server:

func getAndPostDiagnosisKeys(testResult: TestResult, completion: @escaping (Error?) -> Void) {
    manager.getDiagnosisKeys { temporaryExposureKeys, error in
        if let error = error {
            completion(error)
        } else {
            // In this sample app, transmissionRiskLevel isn't set for any of the diagnosis keys. However, it is at this point that an app could
            // use information accumulated in testResult to determine a transmissionRiskLevel for each diagnosis key.
            Server.shared.postDiagnosisKeys(temporaryExposureKeys!) { error in
                completion(error)
            }
        }
    }
}

The sample app also uses a background task to periodically check exposure for users having no COVID-19 diagnosis. The background task identifier shall end in .exposure-notification, which ensures it automatically receives more background time to complete its operation. Additionally, apps that own such tasks are launched more frequently when they are not running. The background task calls the app's detectExposures method to check if the user got exposed and re-schedules itself:

BGTaskScheduler.shared.register(forTaskWithIdentifier: AppDelegate.backgroundTaskIdentifier, using: .main) { task in
    
    // Notify the user if bluetooth is off
    ExposureManager.shared.showBluetoothOffUserNotificationIfNeeded()
    
    // Perform the exposure detection
    let progress = ExposureManager.shared.detectExposures { success in
        task.setTaskCompleted(success: success)
    }
    
    // Handle running out of time
    task.expirationHandler = {
        progress.cancel()
        LocalStore.shared.exposureDetectionErrorLocalizedDescription = NSLocalizedString("BACKGROUND_TIMEOUT", comment: "Error")
    }
    
    // Schedule the next background task
    self.scheduleBackgroundTaskIfNeeded()
}

As a final remark, the Exposure Notification framework provides a way to estimate risk each time a contact is detected. This takes into account when the interaction took place and how long it lasted based on the detected device proximity. The app can alter how risk is estimated by providing an ENExposureConfiguration object, which will be usually sent by the server, and eventually call finish to update the local store and complete the search. The ENExposureConfiguration object supports parameters such as a minimum risk, transmission risk, contact duration, days since last exposure, and a few more.

The ENExposureConfiguration object is passed to the ENManager singleton detectExposures(configuration:diagnosisKeyURLs:completionHandler:) method. For each detected exposure, the app can get additional information using getExposureInfo(summary:userExplanation:completionHandler:):

Server.shared.getExposureConfiguration { result in
    switch result {
    case let .success(configuration):
        ExposureManager.shared.manager.detectExposures(configuration: configuration, diagnosisKeyURLs: localURLs) { summary, error in
            if let error = error {
                finish(.failure(error))
                return
            }
            let userExplanation = NSLocalizedString("USER_NOTIFICATION_EXPLANATION", comment: "User notification")
            ExposureManager.shared.manager.getExposureInfo(summary: summary!, userExplanation: userExplanation) { exposures, error in
                    if let error = error {
                        finish(.failure(error))
                        return
                    }
                    let newExposures = exposures!.map { exposure in
                        Exposure(date: exposure.date,
                                 duration: exposure.duration,
                                 totalRiskScore: exposure.totalRiskScore,
                                 transmissionRiskLevel: exposure.transmissionRiskLevel)
                    }
                    finish(.success((newExposures, nextDiagnosisKeyFileIndex + localURLs.count)))
            }
        }
        
    case let .failure(error):
        finish(.failure(error))
    }
}

The Exposure Notification API requires iOS 13.5 and Xcode 11.5.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • Contact tracing cobnserns

    by Wayne Scott,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Users are concerned with apple iphone ios virus contact tracing privacy. What can done to remove/disable the ios software?

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT