kvs-coder / HealthKitReporter

HealthKitReporter. A wrapper for HealthKit framework. Helps to write or read data from Apple Health via HealthKit framework.
https://cocoapods.org/pods/HealthKitReporter
MIT License
69 stars 19 forks source link

Support for non-String fields in metadata like HKMetadataKeySyncVersion #17

Open umangsh opened 2 years ago

umangsh commented 2 years ago

Is your feature request related to a problem? Please describe. Harmonized.metadata uses [String: String] map for field representation. This fails for metadata fields like HKMetadataKeySyncVersion which expect an NSNumber. Presumably affects other NSNumber fields like HKMetadataKeyReferenceRangeLowerLimit, etc.

Describe the solution you'd like Quantity.Harmonized.metadata should not fail when setting {'HKMetadataKeySyncVersion': 123} and writing to healthKit on device.

umangsh commented 2 years ago

Hi, following up to see if the problem description is clear. There are more details in https://github.com/VictorKachalov/health_kit_reporter/issues/46 - it reads like a debug log, but I'm happy to clarify any details you'd like.

In the meantime, is there is a workaround to write HKMetadataKeySyncVersion to apple health in quantity samples ?

umangsh commented 2 years ago

Hi, just checking in: were you able to look at this bug ? @VictorKachalov

kvs-coder commented 2 years ago

Hi @umangsh

Thank you for your message. Unfortunately I didn't yet have time to take a look at the issue.

Have you tried to provide any local fixes? If so It could be a good opportunity to open a PR, if not I will try this week

umangsh commented 2 years ago

Thanks! My local fixes didn't work unfortunately.

umangsh commented 2 years ago

@VictorKachalov were you able to look at this bug last week?

umangsh commented 1 year ago

@VictorKachalov checking in, any luck with this bug?

kvs-coder commented 1 year ago

Hi @umangsh

Please sorry for my late response, unfortunately couldn't make it for the deeper investigation due to the lack of time last months.

The original HK metadata expects one of the three possible types: NSString, NSDate, NSNumber and these Obj-C types unfortunately are not Codable friendly. But I can use Swift's String, Date, Double instead.

I am seeking the possibility to bring a clean solution combining these types in one metadata property, but currently don't have any ideas.

As a fallback solution, I could extend the amount of metadata properties like:

let metadataString: [String: String]?
let metadataDate: [String: Date]?
let metadataDouble: [String: Double]?
umangsh commented 1 year ago

@VictorKachalov Makes sense, thanks for the explanation. Fallback solution sounds reasonable as a short term fix.

kvs-coder commented 1 year ago

Hi @umangsh

please check the latest 2.0.0 version (Metadata revamp potentially introduces breaking change, but I prepared a fallback solution to avoid errors because ExpressibleByDictionaryLiteral)

umangsh commented 1 year ago

@VictorKachalov Awesome, thank you! I'm using the API through health_kit_reporter (https://github.com/VictorKachalov/health_kit_reporter), which is still at 2.0.4. Mind updating the flutter plugin?

umangsh commented 1 year ago

@VictorKachalov Thanks! I was able to update the plugin version (2.1.0) and pod version (2.0.0) - I think it's improved, but doesn't work quite yet - HKMetadataKeySyncIdentifier and HKMetadataKeySyncVersion values aren't written to Apple Health.

  1. Code that initiates the writes in flutter: https://github.com/umangsh/famnom_flutter/blob/main/packages/healthkit/lib/src/healthkit.dart#L108

  2. Printing the values in Quantity.swift shows the metadata values as nil:

extension Quantity.Harmonized: Payload {
    public static func make(from dictionary: [String: Any]) throws -> Quantity.Harmonized {
        guard
            let value = dictionary["value"] as? NSNumber,
            let unit = dictionary["unit"] as? String
        else {
            throw HealthKitError.invalidValue("Invalid dictionary: \(dictionary)")
        }
        print("dict")
        print(dictionary["metadata"])
        let metadata = dictionary["metadata"] as? [String: Any]
        print("converted")
        print(metadata)
        print("cast")
        print(metadata?.asMetadata)
        return Quantity.Harmonized(
            value: Double(truncating: value),
            unit: unit,
            metadata: metadata?.asMetadata
        )

Sample outputs:

dict
Optional({
    HKMetadataKeySyncIdentifier = "FAMNOM-2022-10-30-1087";
    HKMetadataKeySyncVersion = 1667147391558;
})
converted
Optional(["HKMetadataKeySyncIdentifier": FAMNOM-2022-10-30-1087, "HKMetadataKeySyncVersion": 1667147391558])
cast
nil ---> Didn't expect this to be nil
umangsh commented 1 year ago

@VictorKachalov was the previous message helpful? Let me know if I can provide any more info.

kvs-coder commented 1 year ago

hi @umangsh I will check this, thank you for the input. Have you tried to do this with this native HealthKitReporter? Does HealthKit also ignore the data during writing?

umangsh commented 1 year ago

@VictorKachalov Just the two fields - HKMetadataKeySyncIdentifier and HKMetadataKeySyncVersion, other values are written fine.

umangsh commented 1 year ago

@kvs-coder still an issue. I wonder if Double and NSNumber are causing issues. Here's a small snippet to reproduce in flutter:

 final data = Quantity(
        '',
        QuantityType.dietaryEnergyConsumed.identifier,
        1676048055148,
        1676048055148,
        null,
        const SourceRevision(
          Source('appTitle', 'appBundle'),
          null,
          null,
          '',
          OperatingSystem(0, 0, 0),
        ),
        QuantityHarmonized(1504, 'kcal', <String, dynamic>{
          'HKMetadataKeySyncVersion':
              DateTime.now().millisecondsSinceEpoch,
          'HKMetadataKeySyncIdentifier':
              'appTitle-2023-02-09-100',
        }),
      );
await HealthKitReporter.save(data);

HKMetadataKeySyncVersion and HKMetadataKeySyncIdentifier are not written to apple health. These fields are required for de-duping:

Screenshot 2023-02-10 at 9 45 56 AM