Skip to content

Commit 7bfef8b

Browse files
committed
Fix [health 13.1.4] App crashes on launch with DYLD Symbol missing on iOS 16
Fixes #467 and [health 12.0.1] add support for getChanges/change token Fixes #60
1 parent 72e188c commit 7bfef8b

19 files changed

+453
-26
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
## 13.3.0
22

33
* Add support for `WORKOUT_ROUTE` - PR [#454](https://github.com/carp-dk/carp-health-flutter/pull/454)
4+
* iOS: Fix issues with app crashing on iOS 15
5+
* iOS: Add support for `AppleSleepingWristTemperature` - PR [#468](https://github.com/carp-dk/carp-health-flutter/pull/468)
46
* Android: Add support for `ActivityIntensityRecord` (READ/WRITE/Aggregate)
7+
* Android: Add support for `SkinTemperatureRecord` (READ/WRITE)
58
* Update to `androidx.health.connect:connect-client:1.2.0-alpha02`
69

710
## 13.2.1

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ The plugin supports the following [`HealthDataType`](https://pub.dev/documentati
463463
| MENSTRUATION_FLOW | NO_UNIT | yes | yes | |
464464
| WATER_TEMPERATURE | DEGREE_CELSIUS | yes | | Related to/Requires Apple Watch Ultra's Underwater Diving Workout |
465465
| SLEEP_WRIST_TEMPERATURE | DEGREE_CELSIUS | yes | | READ Only - `appleSleepingWristTemperature` |
466+
| SKIN_TEMPERATURE | DEGREE_CELSIUS | | yes | Must check health connect for availability |
466467
| UNDERWATER_DEPTH | METER | yes | | Related to/Requires Apple Watch Ultra's Underwater Diving Workout |
467468
| UV_INDEX | COUNT | yes | | |
468469
| LEAN_BODY_MASS | KILOGRAMS | yes | yes | |

android/src/main/kotlin/cachet/plugins/health/HealthConstants.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ object HealthConstants {
3838
const val TOTAL_CALORIES_BURNED = "TOTAL_CALORIES_BURNED"
3939
const val SPEED = "SPEED"
4040
const val ACTIVITY_INTENSITY = "ACTIVITY_INTENSITY"
41+
const val SKIN_TEMPERATURE = "SKIN_TEMPERATURE"
4142

4243
// Meal types
4344
const val BREAKFAST = "BREAKFAST"
@@ -106,6 +107,7 @@ object HealthConstants {
106107
MENSTRUATION_FLOW to MenstruationFlowRecord::class,
107108
SPEED to SpeedRecord::class,
108109
ACTIVITY_INTENSITY to ActivityIntensityRecord::class,
110+
SKIN_TEMPERATURE to SkinTemperatureRecord::class,
109111
)
110112

111113
/**
@@ -128,6 +130,7 @@ object HealthConstants {
128130
SLEEP_IN_BED to SleepSessionRecord.SLEEP_DURATION_TOTAL,
129131
TOTAL_CALORIES_BURNED to TotalCaloriesBurnedRecord.ENERGY_TOTAL,
130132
ACTIVITY_INTENSITY to ActivityIntensityRecord.INTENSITY_MINUTES_TOTAL,
133+
SKIN_TEMPERATURE to SkinTemperatureRecord.TEMPERATURE_DELTA_AVG,
131134
)
132135

133136
/**

android/src/main/kotlin/cachet/plugins/health/HealthDataChanges.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class HealthDataChanges(
157157
is ActiveCaloriesBurnedRecord -> listOf(HealthConstants.ACTIVE_ENERGY_BURNED)
158158
is HeartRateRecord -> listOf(HealthConstants.HEART_RATE)
159159
is BodyTemperatureRecord -> listOf(HealthConstants.BODY_TEMPERATURE)
160+
is SkinTemperatureRecord -> listOf(HealthConstants.SKIN_TEMPERATURE)
160161
is BodyWaterMassRecord -> listOf(HealthConstants.BODY_WATER_MASS)
161162
is BloodPressureRecord ->
162163
listOf(

android/src/main/kotlin/cachet/plugins/health/HealthDataConverter.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,32 @@ class HealthDataConverter {
4343
"KELVIN" -> record.temperature.inCelsius + 273.15
4444
else -> record.temperature.inCelsius
4545
}))
46+
is SkinTemperatureRecord -> {
47+
val baselineCelsius = record.baseline?.inCelsius
48+
val baselineValue = when (dataUnit) {
49+
"DEGREE_FAHRENHEIT" -> baselineCelsius?.let { (it * 9.0 / 5.0) + 32.0 }
50+
"KELVIN" -> baselineCelsius?.let { it + 273.15 }
51+
else -> baselineCelsius
52+
}
53+
54+
record.deltas.map { skinDelta ->
55+
val deltaCelsius = skinDelta.delta.inCelsius
56+
val deltaValue = when (dataUnit) {
57+
"DEGREE_FAHRENHEIT" -> deltaCelsius * 9.0 / 5.0
58+
"KELVIN" -> deltaCelsius
59+
else -> deltaCelsius
60+
}
61+
62+
createInstantRecord(metadata, skinDelta.time, deltaValue).toMutableMap().apply {
63+
put("temperature_delta", deltaValue)
64+
put("baseline", baselineValue)
65+
put("measurement_location", record.measurementLocation)
66+
if (baselineValue != null) {
67+
put("temperature", baselineValue + deltaValue)
68+
}
69+
}
70+
}
71+
}
4672
is BodyWaterMassRecord -> listOf(createInstantRecord(metadata, record.time, record.mass.inKilograms))
4773
is OxygenSaturationRecord -> listOf(createInstantRecord(metadata, record.time, record.percentage.value))
4874
is BloodGlucoseRecord -> listOf(createInstantRecord(metadata, record.time, when (dataUnit) {

android/src/main/kotlin/cachet/plugins/health/HealthDataOperations.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,23 @@ class HealthDataOperations(
166166
}
167167
}
168168

169+
/**
170+
* Checks if Skin Temperature data is available on the current device.
171+
* Availability is device-specific and exposed via Health Connect features.
172+
*
173+
* @param call Method call from Flutter (unused)
174+
* @param result Flutter result callback returning boolean availability status
175+
*/
176+
fun isSkinTemperatureAvailable(call: MethodCall, result: Result) {
177+
scope.launch {
178+
result.success(
179+
healthConnectClient.features.getFeatureStatus(
180+
HealthConnectFeatures.FEATURE_SKIN_TEMPERATURE
181+
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE
182+
)
183+
}
184+
}
185+
169186
/**
170187
* Deletes all health records of a specified type within a given time range. Performs bulk
171188
* deletion based on data type and time window.

android/src/main/kotlin/cachet/plugins/health/HealthDataReader.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ class HealthDataReader(
424424
totalValue = totalValue.inMeters
425425
} else if (totalValue is Energy) {
426426
totalValue = totalValue.inKilocalories
427+
} else if (totalValue is TemperatureDelta) {
428+
totalValue = totalValue.inCelsius
427429
}
428430

429431
val packageNames = durationResult.result.dataOrigins

android/src/main/kotlin/cachet/plugins/health/HealthDataWriter.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,22 @@ class HealthDataWriter(
663663
zoneOffset = null,
664664
metadata = metadata,
665665
)
666+
SKIN_TEMPERATURE ->
667+
SkinTemperatureRecord(
668+
startTime = Instant.ofEpochMilli(startTime),
669+
endTime = Instant.ofEpochMilli(endTime),
670+
startZoneOffset = null,
671+
endZoneOffset = null,
672+
baseline = Temperature.celsius(value),
673+
measurementLocation = SkinTemperatureRecord.MEASUREMENT_LOCATION_UNKNOWN,
674+
deltas = listOf(
675+
SkinTemperatureRecord.Delta(
676+
time = Instant.ofEpochMilli(startTime),
677+
delta = TemperatureDelta.celsius(0.0),
678+
)
679+
),
680+
metadata = metadata,
681+
)
666682
BODY_WATER_MASS ->
667683
BodyWaterMassRecord(
668684
time = Instant.ofEpochMilli(startTime),
@@ -907,6 +923,7 @@ class HealthDataWriter(
907923
private const val ACTIVE_ENERGY_BURNED = "ACTIVE_ENERGY_BURNED"
908924
private const val HEART_RATE = "HEART_RATE"
909925
private const val BODY_TEMPERATURE = "BODY_TEMPERATURE"
926+
private const val SKIN_TEMPERATURE = "SKIN_TEMPERATURE"
910927
private const val BODY_WATER_MASS = "BODY_WATER_MASS"
911928
private const val BLOOD_OXYGEN = "BLOOD_OXYGEN"
912929
private const val BLOOD_GLUCOSE = "BLOOD_GLUCOSE"

android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
149149
dataOperations.isHealthDataInBackgroundAuthorized(call, result)
150150
"requestHealthDataInBackgroundAuthorization" ->
151151
requestHealthDataInBackgroundAuthorization(call, result)
152+
"isSkinTemperatureAvailable" ->
153+
dataOperations.isSkinTemperatureAvailable(call, result)
152154

153155
// Reading data
154156
"getData" -> dataReader.getData(call, result)

example/android/app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
<uses-permission android:name="android.permission.health.WRITE_MENSTRUATION"/>
5858
<uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS"/>
5959
<uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS"/>
60+
<uses-permission android:name="android.permission.health.READ_SKIN_TEMPERATURE"/>
61+
<uses-permission android:name="android.permission.health.WRITE_SKIN_TEMPERATURE"/>
6062

6163
<!-- For reading historical data - more than 30 days ago since permission given -->
6264
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>

0 commit comments

Comments
 (0)