flutter-plugins icon indicating copy to clipboard operation
flutter-plugins copied to clipboard

[Health 4.0.0] Write Mindfulness error Could not cast value of type 'HKCategoryType' (0x23f899338) to 'HKQuantityType' (0x23f899310)

Open Horum-dev opened this issue 2 years ago • 2 comments

Hello! Faced this issue in last builds with healthkit 4.0.0 ios deployment target 13.0, device ios version 15.5

Could not cast value of type 'HKCategoryType' (0x23f899338) to 'HKQuantityType' (0x23f899310).
Could not cast value of type 'HKCategoryType' (0x23f899338) to 'HKQuantityType' (0x23f899310).
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x000000021db7ab38 libsystem_kernel.dylib`__pthread_kill + 8
libsystem_kernel.dylib`__pthread_kill:
->  0x21db7ab38 <+8>:  b.lo   0x21db7ab58               ; <+40>
    0x21db7ab3c <+12>: pacibsp 
    0x21db7ab40 <+16>: stp    x29, x30, [sp, #-0x10]!
    0x21db7ab44 <+20>: mov    x29, sp
Target 0: (Runner) stopped.

Flutter doctor:

doctor --verbose
[✓] Flutter (Channel stable, 3.0.2, on macOS 12.3.1 21E258 darwin-x64, locale ru-RU)
    • Flutter version 3.0.2 at /Users/roman/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision cd41fdd495 (8 days ago), 2022-06-08 09:52:13 -0700
    • Engine revision f15f824b57
    • Dart version 2.17.3
    • DevTools version 2.12.2

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Users/roman/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 13.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] VS Code (version 1.67.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.42.0

[✓] Connected device (3 available)
    • Roman’s iPhone (mobile) • 00008101-001C29693644001E • ios            • iOS 15.5 19F77
    • macOS (desktop)         • macos                     • darwin-x64     • macOS 12.3.1 21E258 darwin-x64
    • Chrome (web)            • chrome                    • web-javascript • Google Chrome 102.0.5005.115
    ! Error: Roman’s iPhone is busy: Preparing the watch for development via Roman’s iPhone. Xcode will continue when Roman’s iPhone is finished. (code -10)

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.

code sample:

// create a HealthFactory for use in the app
  final HealthFactory _health = HealthFactory();

  // define the types to get
  final _types = [
    HealthDataType.MINDFULNESS,
  ];
  final _permissions = [HealthDataAccess.WRITE];


 writeMindfulness(int seconds) {
final requestResult2 = await HealthFactory.hasPermissions(_types, permissions: _permissions);
    if (requestResult2) {
      try {
        _health.writeHealthData(
          //tried to pass 0 - worked later, now 0 or N return the same thing
            seconds / 60,
            _types.first,
            DateTime.fromMillisecondsSinceEpoch(
                (DateTime
                    .now()
                    .millisecondsSinceEpoch -
                    Duration(seconds: seconds).inMilliseconds)),
            DateTime.now());
      } catch(e){
        log("writeMindfulness ERROR $e");
      }
    }
  }

the mindfulness minutes doesn’t appear in the health app

Horum-dev avatar Jun 16 '22 09:06 Horum-dev

I have the same issue.

The bug is in SwiftHealthPlugin in line 267.

        if (unitLookUp(key: type) == HKUnit.init(from: "")) {
            sample = HKCategorySample(type: dataTypeLookUp(key: type) as! HKCategoryType, value: Int(value), start: dateFrom, end: dateTo)
        } else {
            let quantity = HKQuantity(unit: unitDict[unit]!, doubleValue: value)
            
            sample = HKQuantitySample(type: dataTypeLookUp(key: type) as! HKQuantityType, quantity: quantity, start: dateFrom, end: dateTo)
        }

Line 718 says

            dataTypesDict[MINDFULNESS] = HKSampleType.categoryType(forIdentifier: .mindfulSession)!

@bardram would you know how to fix this bug?

nohli avatar Jun 30 '22 03:06 nohli

managed to make it work for sleep by changing to this code

`var sample: HKObject? if (unitLookUp(key: type) == HKUnit.init(from: "")) { sample = HKCategorySample(type: dataTypeLookUp(key: type) as! HKCategoryType, value: Int(value), start: dateFrom, end: dateTo) } else { let quantity = HKQuantity(unit: unitDict[unit]!, doubleValue: value)

        switch type {
        case SLEEP_ASLEEP:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.asleep.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        case SLEEP_AWAKE:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.awake.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        case SLEEP_IN_BED:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.inBed.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        default:
            sample = HKQuantitySample(type: dataTypeLookUp(key: type) as! HKQuantityType, quantity: quantity, start: dateFrom, end: dateTo)
        }
        
        

        
    }
    
    if let sample = sample {
        HKHealthStore().save(sample, withCompletion: { (success, error) in
            if let err = error {
                print("Error Saving \(type) Sample: \(err.localizedDescription)")
            }
            DispatchQueue.main.async {
                result(success)
            }
        })
    }
    else {
        print("Error Saving \(type) Sample is null")
    }

you can add a new case ofr mindfulness

mariusgab avatar Sep 06 '22 07:09 mariusgab

managed to make it work for sleep by changing to this code

`var sample: HKObject? if (unitLookUp(key: type) == HKUnit.init(from: "")) { sample = HKCategorySample(type: dataTypeLookUp(key: type) as! HKCategoryType, value: Int(value), start: dateFrom, end: dateTo) } else { let quantity = HKQuantity(unit: unitDict[unit]!, doubleValue: value)

        switch type {
        case SLEEP_ASLEEP:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.asleep.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        case SLEEP_AWAKE:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.awake.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        case SLEEP_IN_BED:
            if let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
                sample = HKCategorySample(
                    type: categoryType,
                    value: HKCategoryValueSleepAnalysis.inBed.rawValue,
                    start: dateFrom,
                    end: dateTo
                )
            }
        default:
            sample = HKQuantitySample(type: dataTypeLookUp(key: type) as! HKQuantityType, quantity: quantity, start: dateFrom, end: dateTo)
        }
        
        

        
    }
    
    if let sample = sample {
        HKHealthStore().save(sample, withCompletion: { (success, error) in
            if let err = error {
                print("Error Saving \(type) Sample: \(err.localizedDescription)")
            }
            DispatchQueue.main.async {
                result(success)
            }
        })
    }
    else {
        print("Error Saving \(type) Sample is null")
    }

you can add a new case ofr mindfulness

Not working, dataTypeLookUp(key: type) return a object with type HKCategoryType

lau1944 avatar Nov 15 '22 00:11 lau1944

FYI as a workaround, I've created a plugin just for mindful minutes: https://pub.dev/packages/mindful_minutes

nohli avatar Nov 15 '22 12:11 nohli

FYI as a workaround, I've created a plugin just for mindful minutes: https://pub.dev/packages/mindful_minutes

I tried it, iOS 16 is not supported.

lau1944 avatar Nov 15 '22 16:11 lau1944

@lau1944 what do you mean? I'm using it in a production app and just checked, the app successfully writes mindful minutes on the latest iOS version.

nohli avatar Nov 15 '22 16:11 nohli

@nohli the requestPermission method did not navigate to any permission page, and always return false.

lau1944 avatar Nov 16 '22 00:11 lau1944

@lau1944 but do you see the app under Settings - Privacy & Security - Health, with disabled toggles? On iOS, it asks only one time and then the user has to manually edit permissions in iOS settings (just checked with other apps) This behavior was prior to iOS 16.

nohli avatar Nov 16 '22 08:11 nohli

@nohli I could not iOS sample on the repo, can you send me what you declare on info.plis?

lau1944 avatar Nov 19 '22 22:11 lau1944

@lau1944 let me google that for you:

	<key>NSHealthUpdateUsageDescription</key>
	<string>Some explanation</string>

nohli avatar Nov 20 '22 08:11 nohli

Thanks !

lau1944 avatar Nov 21 '22 16:11 lau1944