Skip to main content

RookSDK

If you’re building a health or fitness application of any kind, you likely understand the power of health user data. Integrating it with your application will benefit you regardless of your use case, whether it’s mindfulness and wellness, digital health, or remote care.

Apple Health does not have an API, and since no data is stored in the cloud, you need to retrieve it locally from your users' devices. This can be done by implementing Apple HealthKit and its data retrieval methods into your iOS app.

ROOK SDK allows developers to ask their users to access and share their health data through Apple HealthKit.

ROOK SDK for iOS enables fetching health data from Apple Health and synchronizing it with the ROOK server. It also allows registering a new user and storing this information locally.

The SDK provides access to Apple Health data, but only after the user's explicit consent. Users can select detailed data sharing settings, including which data types will be read.

Demo app

To help your implementation here is a demo app that shows you how to configure and use the sdk: https://github.com/RookeriesDevelopment/rook_demo_app_ios_rook_sdk

Features

The features listed bellow are available to fetch and synchronize:

  • Sleep summaries
  • Physical summaries
  • Body summaries
  • Heart rate events
  • Oxygenation events
  • Activity events
  • Temperature Events
  • Blood Glucose Events
  • Blood Pressure Events
  • Time zone of the device
  • Variable extraction
  • Background active extraction

Integrating the iOS framework


Installation

The SDK requires Xcode 14.0.1 or higher. To run your app using the Rook SDK on a connected device with iOS 13.0 or later you need Xcode 14.2 or higher.

To add a package dependency to your Xcode project, select File > Swift Packages > Add Package Dependency and enter the repository URL rook SDK

Rook SDK supports installation with CocoaPods

Here's how to install Rook using CocoaPods:

  • Create a Podfile if you don't already have one. From the root of your project directory, run the following command:
  pod init
  • To your Podfile, add the Rook pod
  pod "RookSDK"
  • Install the pods, then open your .xcworkspace file to see the project in Xcode:
  pod install

Configuration

To configure Rook SDK, you need to follow this steps:

  1. Import the apple health sdk
import RookSDK
  1. Add your credentials.
  • This method should be called at the beginning of your app's launch process.
func application(_ application: UIApplication
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

RookConnectConfigurationManager.shared.setConfiguration(
clientUUID: "YOUR-CLIENT-UUID",
secretKey: "YOUR-SECRET-KEY",
enableBackgroundSync: true,
enableEventsBackgroundSync: true)

RookConnectConfigurationManager.shared.setEnvironment(.sandbox)

RookConnectConfigurationManager.shared.initRook()
return true
}
  1. Add the HealthKit framework to your Xcode project:
  • Open your project in Xcode.
  • Click on your project file in the Project Navigator.
  • Select your target and then click on the "Build Phases" tab.
  • Click on the "+" button under the "Link Binary With Libraries" section and select "HealthKit.framework" from the list.

rook_connect_configuraiton

  1. Then declare the privacy permissions used by this SDK. You will need to include the NSHealthShareUsageDescription and NSHealthUpdateUsageDescription keys in your app's Info.plist file. These keys provide a description of why your app needs to access HealthKit data and will be displayed to the user in the permission request dialog.
<key>NSHealthShareUsageDescription</key>
<string>This app requires access to your health and fitness data in order to track your workouts and activity levels.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>This app requires permission to write health data to HealthKit.</string>

infoplist

RookConnectConfigurationManager Use this class to configure and init the sdk. This class conforms the singleton pattern, to access this class use the shared property.

MethodDescription
func setConfiguration(clientUUID: String, secretKey: String, enableBackgroundSync: Bool, enableEventsBackgroundSync: Bool)Sets the configuration of the sdk.
func setEnvironment(_ environment: RookEnvironment)Configures the rook sdk environment.
func initRook()Initializes the rook sdk
func updateUserId(_ id: String, completion: @escaping (Result<Bool, Error>) -> Void)It will try to register the user in the rook server and it will be stored, if the registration was successful, after that the sdk upload the current time zone of the device.
func getUserId(completion: @escaping (Result<String, Error>) -> Void)Returns the user id stored locally.
func clearUser(completion: @escaping (Result<Bool, Error>) -> Void)Deletes the user stored locally.
func removeUserFromRook(completion: @escaping (Result<Bool, Error>) -> Void)Removes the authorization od the user to upload data from apple health and deletes the user id stored locally.
func syncUserTimeZone(completion: @escaping (Result<Bool, Error>) -> Void)Uploads the current time zone of the device a user has to added before use this method.
func enableSync()This method enables the automatic upload of the missing summaries from previous days. Every time the user opens the app it will try to upload the summaries, before use this method is necessary to add a user id and request all permissions.
func disableSync()This method disables the automatic upload of the summaries from the previous days.
func isSyncEnable() -> BoolReturns a boolean indicating if the automatic upload is enable.
func setConsoleLogAvailable(_ value: Bool)Enables or disables console logs for transmission responses when uploading events or summaries.
info

The parameters enableBackgroundSync and enableEventsBackgroundSync enable background synchronization for summaries and events, respectively. To disable synchronization for either, set the corresponding parameter to false.

Get user authorization

Before you can retrieve any data, your app needs to be authorized to access Apple Health data by your users. To get authorization, use the authorize method, and the corresponding dialog will be shown on top of your app.

health_permissions

The SDK provides the RookConnectPermissionsManager class to request user permission. It contains the following methods:

MethodDescription
+ requestAllPermissions(completion: @escaping (Result<Bool, Error>) -> Void)Sends a request for all the health permissions and displays a view to grand access
+ requestSleepPermissions(completion: @escaping (Result<Bool, Error>) -> Void)Sends a request for the sleep data types permissions and displays a view to grand access.
+ requestUserInfoPermissions(completion: @escaping (Result<Bool, Error>) -> Void)Sends a request for the user information permissions.
+ requestPhysicalPermissions(completion: @escaping (Result<Bool, Error>) -> Void)Sends a request for the physical data types permissions and displays a view to grand access
+ requestBodyPermissions(completion: @escaping (Result<Bool, Error>) -> Void)Sends a request for the body data type permissions and displays a view to grand access.
info

The callback of each method returns a boolean: true if the permission window was successfully presented, or false with an optional error if the window was not presented properly. This value does not indicate whether the user actually granted permission. Please keep in mind that Apple Health does not allow checking the status of permissions for types requested to be read. If the user does not allow data type reading, either by mistake or on purpose, it will simply appear as if there is no data of the requested type in the HealthKit store. Any further changes must be performed by the user through the Apple Health application.

User

Before synchronize summaries or events a user have to be added, otherwise the sdk will return an error.

The class UserManager contains the below methods related to the user access.

MethodDescription
func updateUserId(_ id: String, completion: @escaping (Result<Bool, Error>) -> Void)It will try to register the user in the rook server and it will be stored, if the registration was successful, after that the sdk upload the current time zone of the device.
func getUserId(completion: @escaping (Result<String, Error>) -> Void)Return the user id stored locally.
func clearUser(completion: @escaping (Result<Bool, Error>) -> Void)Deletes the user stored locally.
func removeUserFromRook(completion: @escaping (Result<Bool, Error>) -> Void)Removes the authorization od the user to upload data from apple health and deletes the user id stored locally.
public func syncUserTimeZone(completion: @escaping (Result<Bool, Error>) -> Void)Uploads the current time zone of the device a user has to added before use this method.
func revokeDataSource(dataSource: DataSourceRevoke, completion: @escaping (Result<Bool, Error>) -> Void)Revoke the authorization of the data source given.

Async await is supported.

MethodDescription
public func updateUserId(_ id: String) async throws -> BoolIt will try to register the user in the rook server and it will be stored, if the registration was successful, after that the sdk upload the current time zone of the device.
public func getUserId() async throws -> StringReturn the user id stored locally.
public func clearUser() async throws -> BoolDeletes the user stored locally.
public func removeUserFromRook() async throws -> BoolRemoves the authorization od the user to upload data from apple health and deletes the user id stored locally.
public func syncUserTimeZone() async throws -> BoolUploads the current time zone of the device a user has to added before use this method.
func revokeDataSource(dataSource: DataSourceRevoke) async throws -> BoolRevoke the authorization of the data source given.
info

Any call to upbdateUserId with a different userId will override the previous userID and reset the sync status, if you are using BackgroundSync all health data will synchronize again the next time the app is launched.

Continuous Upload


The class RookConnectConfigurationManager contains two methods to enable or disable continuous data upload. every time a user opens the app, the sdk will try to upload the data from the previous day of the device's current date.

Note: before enable this feature it is necessary to add a user a request permission from apple health

MethodDescription
func enableSync()This method enables the automatic upload, it will check the last time data was synced. If there is new data to update or pending data from previous days, it will upload this information., before use this method is necessary to add a user id and request permissions.
func disableSync()This method disables the automatic upload of the summaries.

Background Upload


RookBackGroundSync

The class RookBackGroundSync contains methods to enable background uploads for summaries, allowing your app to upload health data while it is in the background. It is recommended to combine continuous upload, background upload, and manual sync for better performance.

info

For security, iOS devices encrypt the HealthKit storage when users lock their devices. As a result, apps may not be able to read data from Apple Health when running in the background. Please refer to the official documentation for more information.

MethodDescription
func setBackListeners()This method has to be added in app delegate to enable back ground upload.
func enableBackGroundForSummaries()This method enables the background upload of the summaries.
func disableBackGroundForSummaries()This method disables the background upload of the summaries.
func isBackGroundForEventsEnable() -> BoolThis method returns the status of background upload for summaries.
func enableBackGroundForEvents()This method enables the background upload of the events.
func disableBackGroundForEvents()This method disables the background upload of the events.
func isBackGroundForEventsEnable() -> BoolThis method returns the status of background upload for events.

To configure background upload you need to follow the steps bellow:

  • Add health kit to your project and enable background delivery.
  • Add Background modes and enable Background fetch.

background_delivery

  • In the app delegate of your app add the setBackListeners() method in didFinishLaunchingWithOptions function.

Example


import RookSDK

class AppDelegate: NSObject, UIApplicationDelegate {

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
RookBackGroundSync.shared.setBackListeners()
}

Background notifications error

When an error occurs in a back ground proccess, it can be listen by adding an observer, as shown in the example below:

import RookSDK

func onAppear() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handleErrorBackground),
name: NSNotification.Name.init(EventNames.errorBackGround),
object: nil)
}

@objc private func handleErrorBackground(_ notification: Notification) {
if let data: [AnyHashable : Any] = notification.userInfo {
debugPrint(data)
}
}

Manual Sync Data


RookSummaryManager

This class contains the methods to synchronize summaries of the user

MethodDescription
func syncSummaries(completion: @escaping () -> Void)Uploads the sleep, physical and body summaries of previous days that has no been uploaded.
func syncSleepSummary(form date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronizes the sleep summary from the given day date.
func syncPhysicalSummary(form date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronizes the physical summary from the given day date.
func syncBodySummary(from date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronizes the body summary from the given day date.

Async await implementation is also supported

MethodDescription
public func syncSummaries() asyncUploads the sleep, physical and body summaries of previous days that has no been uploaded.
public func syncSleepSummary(from date: Date) async throws -> BoolSynchronizes the sleep summary from the given day date.
public func syncPhysicalSummary(from date: Date) async throws -> BoolSynchronizes the physical summary from the given day date.
public func syncBodySummary(from date: Date) async throws -> BoolSynchronizes the body summary from the given day date.

RookEventsManager

MethodDescription
func syncEvents(completion: @escaping () -> Void)Uploads all the events of previous days that has no been uploaded.
func syncBodyHeartRateEvent(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the body heart rate events from the given day date.
func syncPhysicalHeartRateEvent(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the physical heart rate events from the given day date.
func syncBodyOxygenationEvent(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the body oxygenation events from the given day date.
func syncPhysicalOxygenationEvent(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the physical oxygenation events from the given day date.
func syncTrainingEvent(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the trainings events from the given day date.
func syncTemperatureEvents(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the temperature events from the given day date.
func syncBloodPressureEvents(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the blood pressure events from the given day date.
func syncBloodGlucoseEvents(date: Date, completion: @escaping (Result<Bool, Error>) -> Void)Synchronized all the blood glucose events from the given day date.
getTodayStepCount(completion: @escaping (Result<Int, Error>) -> Void)"Upload the current step count retrieved from Apple Health as a steps event, and return the current count or an error in the completion response.

Async await implementation is also supported

MethodDescription
public func syncEvents() asyncUploads all the events of previous days that has no been uploaded.
public func syncBodyHeartRateEvent(date: Date) async throws -> BoolSynchronized all the body heart rate events from the given day date.
public func syncPhysicalHeartRateEvent(date: Date) async throws -> BoolSynchronized all the physical heart rate events from the given day date.
public func syncBodyOxygenationEvent(date: Date) async throws -> BoolSynchronized all the body oxygenation events from the given day date.
public func syncPhysicalOxygenationEvent(date: Date) async throws -> BoolSynchronized all the physical oxygenation events from the given day date.
public func syncTrainingEvent(date: Date) async throws -> BoolSynchronized all the trainings events from the given day date.
public func syncTemperatureEvents(date: Date) async throws -> BoolSynchronized all the temperature events from the given day date.
public func syncBloodPressureEvents(date: Date) async throws -> BoolSynchronized all the blood pressure events from the given day date.
public func syncBloodGlucoseEvents(date: Date) async throws -> BoolSynchronized all the blood glucose events from the given day date.
public func syncBodyMetricsEvents(date: Date) async throws -> BoolSynchronized all the body metrics events from the given day date.
public func getTodayStepCount() async throws -> Int"Upload the current step count retrieved from Apple Health as a steps event, returns the current count or throws an error.
danger

We highly advise against retrieving more than 14 days of EPOCH data and 30 days of Daily data for more than one data type. Due to the expected volume of data, the retrieval process will require extensive resources and may affect the user experience.

Data Sources

ROOK SDK includes the class DataSourcesManager, which allows the presentation of a connection page view where users can directly connect other data sources with ROOK. If you prefer to implement your own view, this class also contains a method to retrieve the available data sources for connection.

MethodDescription
func getAvailableDataSources(redirectURL: String?, completion: @escaping (Result<[RookDataSource], Error>) -> Void)Retrieves and array of object representing the available data sources.
func presentDataSourceView(redirectURL: String?, completion: @escaping (Result<Bool, Error>) -> Void)Presents a view that contains the available data sources.