Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Healthkit background delivery when app is not running

Can HealthKit background delivery launch the application if is not running? Particularly in a terminated state?

like image 244
TechSeeker Avatar asked Oct 15 '14 06:10

TechSeeker


People also ask

Is HealthKit secure?

Access Encrypted Data For security, the device encrypts the HealthKit store when the user locks the device. As a result, your app may not be able to read data from the store when it runs in the background. However, your app can still write to the store, even when the phone is locked.

How do I activate HealthKit on Apple Watch?

Open the Health app. Tap your profile , then tap Devices. Tap your Apple Watch. Tap Privacy Settings and make sure that Fitness Tracking is turned on.

How does HealthKit store data?

This data is stored in Data Protection class Protected Unless Open. Access to the data is relinquished 10 minutes after device locks, and data becomes accessible the next time user enters their passcode or uses Touch ID or Face ID to unlock the device.

What apps use HealthKit?

The list of apps compatible with HealthKit includes such popular names as: fitness apps — Strava, Runtastic Steps, Garmin Connect. nutrition apps — Lifesum, Foodzy. healthcare apps — HealthyNow, Hello Doctor.


2 Answers

After a full day of testing (iOS 9.2) I can confirm that HealthKit background delivery DOES WORK in all of the following application states:

  • background (in background and executing code),
  • suspended (in background but not executing code),
  • terminated (force-killed by the user or purged by the system).

Keep in mind: part 1

Some HealthKit data types have a minimum update frequency of HKUpdateFrequencyHourly. That said, even if you set up a background delivery with frequency HKUpdateFrequencyImmediate, you won't get updates more often than every hour or so.

Unfortunately, there is no info in documentation about minimum frequencies per data types, but my experience with Fitness types was as follows:

  • Active Energy: hourly,
  • Cycling Distance: immediate,
  • Flights Climbed: immediate,
  • NikeFuel: immediate,
  • Steps: hourly,
  • Walking + Running Distance: hourly,
  • Workouts: immediate.

Note: immediate DOES NOT mean real-time but rather "some time shortly after" the activity data samples has been written to the HealthKit database/store.

Keep in mind: part 2

If the device is locked with a passcode, none of you background delivery observers will be called. This is intentional due to the privacy concerns (read more: https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HealthKit_Framework/).

That said, as soon as the user unlocks the device, your HealthKit background delivery observers will be called (if the minimum frequency time has passed, of course).

Sample code:

Take a look at Viktor Sigler's answer. Although, you can skip all three steps from the beginning of his answer since they are not required for HealthKit background delivery to work.

like image 94
damirstuhec Avatar answered Oct 02 '22 18:10

damirstuhec


This answer is some late but I hope this help the people to understand how to work with the HKObserverQuery successfully.

First of all the HKObserverQuery works fine in background mode and when the app is closed at all. But you need to set some options first to allow everything works fine.

  1. You need to set the Background Modes in the Capabilities of your app. See below picture:

enter image description here

  1. Then you need to add the Required Background Modes in your info.plist as in the following picture:

enter image description here

  1. You need to set the Background Fetch in the following way:

    3.1. From the Scheme toolbar menu, choose an iOS Simulator or Device.

    3.2. From the same menu, choose Edit Scheme.

    3.3. In the left column, select Run.

    3.4. Select the Options tab.

    3.5. Select the Background Fetch checkbox and click Close.

enter image description here

Then you can receive notifications when the app is in background or closed using the following code:

import UIKit import HealthKit  @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {     var window: UIWindow?     let healthKitStore:HKHealthStore = HKHealthStore()     func startObservingHeightChanges() {         let sampleType =  HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)         var query: HKObserverQuery = HKObserverQuery(sampleType: sampleType, predicate: nil, updateHandler: self.heightChangedHandler)         healthKitStore.executeQuery(query)        healthKitStore.enableBackgroundDeliveryForType(sampleType, frequency: .Immediate, withCompletion: {(succeeded: Bool, error: NSError!) in             if succeeded{                println("Enabled background delivery of weight changes")            } else {                if let theError = error{                    print("Failed to enable background delivery of weight changes. ")                    println("Error = \(theError)")                }            }        })    }      func heightChangedHandler(query: HKObserverQuery!, completionHandler: HKObserverQueryCompletionHandler!, error: NSError!) {                 // Here you need to call a function to query the height change         // Send the notification to the user        var notification = UILocalNotification()        notification.alertBody = "Changed height in Health App"        notification.alertAction = "open"                notification.soundName = UILocalNotificationDefaultSoundName            UIApplication.sharedApplication().scheduleLocalNotification(notification)         completionHandler()    }     func authorizeHealthKit(completion: ((success:Bool, error:NSError!) -> Void)!) {         // 1. Set the types you want to read from HK Store        let healthKitTypesToRead = [         HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierDateOfBirth),         HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierBloodType),         HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierBiologicalSex),         HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass),         HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight),         HKObjectType.workoutType()        ]         // 2. Set the types you want to write to HK Store        let healthKitTypesToWrite = [         HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex),         HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned),         HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning),         HKQuantityType.workoutType()        ]         // 3. If the store is not available (for instance, iPad) return an error and don't go on.        if !HKHealthStore.isHealthDataAvailable() {            let error = NSError(domain: "any.domain.com", code: 2, userInfo: [NSLocalizedDescriptionKey:"HealthKit is not available in this Device"])             if( completion != nil ) {                                completion(success:false, error:error)            }            return;        }         // 4.  Request HealthKit authorization        healthKitStore.requestAuthorizationToShareTypes(Set(healthKitTypesToWrite), readTypes: Set(healthKitTypesToRead)) { (success, error) -> Void in            if( completion != nil ) {                 dispatch_async(dispatch_get_main_queue(), self.startObservingHeightChanges)                completion(success:success,error:error)            }        }    }        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {         application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Badge | .Sound, categories: nil))         self.authorizeHealthKit { (authorized,  error) -> Void in            if authorized {                println("HealthKit authorization received.")            }            else {                println("HealthKit authorization denied!")                if error != nil {                    println("\(error)")                }            }        }         return true    }            //Rest of the defaults methods of AppDelegate.swift     } 

In the above method the HKObserver is activated if the HealthKit authorization is granted by the user and then activate notifications.

I hope this help you.

like image 32
Victor Sigler Avatar answered Oct 02 '22 20:10

Victor Sigler