Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2f40eed
fix metadata parse crash
Jan 20, 2025
c657d52
Merge pull request #1120 from biklas7/bug/crash-fix
iarata Jan 29, 2025
fa5b915
update CHANGELOG for 12.0.2
iarata Jan 29, 2025
709dff0
Merge pull request #1123 from cph-cachet/health-12/1120-metadata
iarata Jan 29, 2025
d2c831d
[Health] Add HC health history permission
cachapa Feb 3, 2025
94b1e42
Add documentation
cachapa Feb 3, 2025
9160f04
Implement check for data history feature
cachapa Feb 4, 2025
a0b03dd
Fix exception message
cachapa Feb 4, 2025
55230ba
Merge branch 'master' into iarata/health-12
iarata Feb 13, 2025
c8c2959
Add Flutter lints, update example apps
iarata Feb 23, 2025
492ad6b
Merge pull request #1142 from cph-cachet:health-12/example-update
iarata Feb 23, 2025
207cabf
Update iOS deployment target to 14.0, bump version to 12.0.2
iarata Feb 23, 2025
01fbc61
Ignore .cxx folder created by Flutter 3.29
iarata Feb 23, 2025
ab1945b
Merge pull request #1143 from cph-cachet/health-12/1120-metadata
iarata Feb 23, 2025
08e11fc
Add iOS UV Index health data types
iarata Feb 27, 2025
4492858
Merge pull request #1147 from cph-cachet/health-12/UV
iarata Feb 27, 2025
9213e2b
Update CHANGELOG
iarata Feb 27, 2025
88d020a
Add UV_INDEX health data type to README
iarata Feb 27, 2025
bf8ea2a
Merge pull request #1148 from cph-cachet/health-12/UV
iarata Feb 27, 2025
1603239
Cleanup CHANGELOG
iarata Feb 27, 2025
db95b02
Merge pull request #1127 from cachapa/health_history
iarata Feb 27, 2025
31e9750
Update Java build to 11, Fragment and Compose-BOM to latest
iarata Mar 1, 2025
84e3bb7
Bump version to 12.1.0, update CHANGELOG; add permissions for reading…
iarata Mar 1, 2025
ae60d93
Update CHANGELOG
iarata Mar 1, 2025
3b74508
Update CHANGELOG
iarata Mar 1, 2025
762fb20
Merge branch 'master' into iarata/health-12
iarata Mar 6, 2025
f2d6d0d
Merge branch 'iarata/health-12' into health-12/1127-hc-history
iarata Mar 6, 2025
74ee520
Merge pull request #1153 from cph-cachet/health-12/1127-hc-history
bardram Mar 13, 2025
2c709c3
Merge branch 'master' into iarata/health-12
iarata Mar 14, 2025
7fb947b
Merge remote-tracking branch 'origin/iarata/health-12' into iarata/he…
iarata Mar 14, 2025
8661b04
Add deleteByUUID method
iarata Mar 16, 2025
52b3b06
Update CHANGELOG
iarata Mar 16, 2025
607fd96
Cleanup
iarata Mar 16, 2025
674b4a0
Merge pull request #1163 from cph-cachet:health-12/delete-uuid
iarata Mar 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,4 @@ packages/app_usage/example/.flutter-plugins-dependencies
packages/app_usage/example/.flutter-plugins-dependencies

.sdkmanrc
**/.cxx/
19 changes: 17 additions & 2 deletions packages/health/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 12.1.0

* Add delete record by UUID method. See function `deleteByUUID(required String uuid, HealthDataType? type)`
* iOS: Parse metadata to remove unsupported types - PR [#1120](https://github.com/cph-cachet/flutter-plugins/pull/1120)
* iOS: Add UV Index Types
* Android: Add request access to historic data [#1126](https://github.com/cph-cachet/flutter-plugins/issues/1126) - PR [#1127](https://github.com/cph-cachet/flutter-plugins/pull/1127)
```XML
<!-- Add the following permission into AndroidManifest.xml -->
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>
```
* Android:
* Update `androidx.compose:compose-bom` to `2025.02.00`
* Update `androidx.health.connect:connect-client` to `1.1.0-alpha11`
* Update `androidx.fragment:fragment-ktx` to `1.8.6`
* Update to Java 11
* Update example apps

## 12.0.1

* Update of API and README doc
Expand All @@ -18,12 +35,10 @@
* Fix [#984](https://github.com/cph-cachet/flutter-plugins/issues/984) - PR [#1055](https://github.com/cph-cachet/flutter-plugins/pull/1055)
* Add `LEAN_BODY_MASS` data type [#1078](https://github.com/cph-cachet/flutter-plugins/issues/1078) - PR [#1097](https://github.com/cph-cachet/flutter-plugins/pull/1097)
* The following AndroidManifest values are required to READ/WRITE `LEAN_BODY_MASS`:

```XML
<uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS"/>
<uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS"/>
```

* iOS: Add `WATER_TEMPERATURE` and `UNDERWATER_DEPTH` health values [#1096](https://github.com/cph-cachet/flutter-plugins/issues/1096)
* iOS: Add support for `Underwater Diving` workout [#1096](https://github.com/cph-cachet/flutter-plugins/issues/1096)
* Fix [#1072](https://github.com/cph-cachet/flutter-plugins/issues/1072) and [#1074](https://github.com/cph-cachet/flutter-plugins/issues/1074)
Expand Down
11 changes: 11 additions & 0 deletions packages/health/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ An example of asking for permission to read and write heart rate data is shown b
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
```

By default, Health Connect restricts read data to 30 days from when permission has been granted.

You can check and request access to historical data using the `isHealthDataHistoryAuthorized` and `requestHealthDataHistoryAuthorization` methods, respectively.

The above methods require the following permission to be declared:

```xml
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>
```

Accessing fitness data (e.g. Steps) requires permission to access the "Activity Recognition" API. To set it add the following line to your `AndroidManifest.xml` file.

```xml
Expand Down Expand Up @@ -362,6 +372,7 @@ The plugin supports the following [`HealthDataType`](https://pub.dev/documentati
| MENSTRUATION_FLOW | NO_UNIT | yes | yes | |
| WATER_TEMPERATURE | DEGREE_CELSIUS | yes | | Related to/Requires Apple Watch Ultra's Underwater Diving Workout |
| UNDERWATER_DEPTH | METER | yes | | Related to/Requires Apple Watch Ultra's Underwater Diving Workout |
| UV_INDEX | COUNT | yes | | |
| LEAN_BODY_MASS | KILOGRAMS | yes | yes | |

## Workout Types
Expand Down
14 changes: 7 additions & 7 deletions packages/health/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 34
compileSdk 34

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '11'
}

sourceSets {
Expand All @@ -51,12 +51,12 @@ android {
}

dependencies {
def composeBom = platform('androidx.compose:compose-bom:2022.10.00')
def composeBom = platform('androidx.compose:compose-bom:2025.02.00')
implementation(composeBom)
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation("androidx.health.connect:connect-client:1.1.0-alpha07")
def fragment_version = "1.6.2"
implementation("androidx.health.connect:connect-client:1.1.0-alpha11")
def fragment_version = "1.8.6"
implementation "androidx.fragment:fragment-ktx:$fragment_version"

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.NonNull
import androidx.health.connect.client.feature.ExperimentalFeatureAvailabilityApi
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.HealthConnectFeatures
import androidx.health.connect.client.PermissionController
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_HISTORY
import androidx.health.connect.client.records.*
import androidx.health.connect.client.records.MealType.MEAL_TYPE_BREAKFAST
import androidx.health.connect.client.records.MealType.MEAL_TYPE_DINNER
Expand Down Expand Up @@ -147,6 +150,9 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
when (call.method) {
"installHealthConnect" -> installHealthConnect(call, result)
"getHealthConnectSdkStatus" -> getHealthConnectSdkStatus(call, result)
"isHealthDataHistoryAvailable" -> isHealthDataHistoryAvailable(call, result)
"isHealthDataHistoryAuthorized" -> isHealthDataHistoryAuthorized(call, result)
"requestHealthDataHistoryAuthorization" -> requestHealthDataHistoryAuthorization(call, result)
"hasPermissions" -> hasPermissions(call, result)
"requestAuthorization" -> requestAuthorization(call, result)
"revokePermissions" -> revokePermissions(call, result)
Expand All @@ -161,6 +167,7 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
"writeBloodOxygen" -> writeBloodOxygen(call, result)
"writeMenstruationFlow" -> writeMenstruationFlow(call, result)
"writeMeal" -> writeMeal(call, result)
"deleteByUUID" -> deleteByUUID(call, result)
else -> result.notImplemented()
}
}
Expand Down Expand Up @@ -512,6 +519,55 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
}
}

/**
* Checks if the health data history feature is available on this device
*/
@OptIn(ExperimentalFeatureAvailabilityApi::class)
private fun isHealthDataHistoryAvailable(call: MethodCall, result: Result) {
scope.launch {
result.success(
healthConnectClient
.features
.getFeatureStatus(HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_HISTORY) ==
HealthConnectFeatures.FEATURE_STATUS_AVAILABLE)
}
}

/**
* Checks if PERMISSION_READ_HEALTH_DATA_HISTORY has been granted
*/
private fun isHealthDataHistoryAuthorized(call: MethodCall, result: Result) {
scope.launch {
result.success(
healthConnectClient
.permissionController
.getGrantedPermissions()
.containsAll(listOf(PERMISSION_READ_HEALTH_DATA_HISTORY)),
)
}
}

/**
* Requests authorization for PERMISSION_READ_HEALTH_DATA_HISTORY
*/
private fun requestHealthDataHistoryAuthorization(call: MethodCall, result: Result) {
if (context == null) {
result.success(false)
return
}

if (healthConnectRequestPermissionsLauncher == null) {
result.success(false)
Log.i("FLUTTER_HEALTH", "Permission launcher not found")
return
}

// Store the result to be called in [onHealthConnectPermissionCallback]
mResult = result
isReplySubmitted = false
healthConnectRequestPermissionsLauncher!!.launch(setOf(PERMISSION_READ_HEALTH_DATA_HISTORY))
}

private fun hasPermissions(call: MethodCall, result: Result) {
val args = call.arguments as HashMap<*, *>
val types = (args["types"] as? ArrayList<*>)?.filterIsInstance<String>()!!
Expand Down Expand Up @@ -2340,6 +2396,43 @@ class HealthPlugin(private var channel: MethodChannel? = null) :
}
}

/** Delete a specific record by UUID and type */
private fun deleteByUUID(call: MethodCall, result: Result) {
val arguments = call.arguments as? HashMap<*, *>
val dataTypeKey = (arguments?.get("dataTypeKey") as? String)!!
val uuid = (arguments?.get("uuid") as? String)!!

if (!mapToType.containsKey(dataTypeKey)) {
Log.w("FLUTTER_HEALTH::ERROR", "Datatype $dataTypeKey not found in HC")
result.success(false)
return
}

val classType = mapToType[dataTypeKey]!!

scope.launch {
try {
healthConnectClient.deleteRecords(
recordType = classType,
recordIdsList = listOf(uuid),
clientRecordIdsList = emptyList()
)
result.success(true)
Log.i(
"FLUTTER_HEALTH::SUCCESS",
"[Health Connect] Record with UUID $uuid was successfully deleted!"
)
} catch (e: Exception) {
Log.e("FLUTTER_HEALTH::ERROR", "Error deleting record with UUID: $uuid")
Log.e("FLUTTER_HEALTH::ERROR", e.message ?: "unknown error")
Log.e("FLUTTER_HEALTH::ERROR", e.stackTraceToString())
result.success(false)
}
}
}



private val mapSleepStageToType =
hashMapOf(
0 to SLEEP_UNKNOWN,
Expand Down
45 changes: 45 additions & 0 deletions packages/health/example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/

# Symbolication related
app.*.symbols

# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
39 changes: 37 additions & 2 deletions packages/health/example/.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,42 @@
# This file should be version controlled and should not be manually edited.

version:
revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5
channel: beta
revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: android
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: ios
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: linux
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: macos
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: web
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: windows
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
28 changes: 28 additions & 0 deletions packages/health/example/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
14 changes: 14 additions & 0 deletions packages/health/example/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/

# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
Loading