Skip to content

add possibility to write records#6

Merged
Kebechet merged 62 commits intoKebechet:mainfrom
Saurus119:add-write-record-functionality
Dec 22, 2025
Merged

add possibility to write records#6
Kebechet merged 62 commits intoKebechet:mainfrom
Saurus119:add-write-record-functionality

Conversation

@Saurus119
Copy link
Copy Markdown
Collaborator

No description provided.

@Saurus119 Saurus119 marked this pull request as draft November 17, 2025 11:49
@Saurus119
Copy link
Copy Markdown
Collaborator Author

Android reflections reasons:

  1. Incomplete Xamarin Bindings (Alpha Quality)

The NuGet package Xamarin.AndroidX.Health.Connect.ConnectClient is version 1.1.0-alpha07 - a prerelease. The bindings are auto-generated
and incomplete:

  • Properties like InKilograms, InCalories, InMeters on unit classes (Mass, Energy, Length) are not exposed
  • The C# binding generator doesn't properly handle all Kotlin patterns
  1. Kotlin Companion Object Pattern

Health Connect SDK uses Kotlin's Companion object for factory methods:
// Kotlin SDK code
val mass = Mass.kilograms(75.0)
val energy = Energy.kilocalories(500.0)

In C#, this becomes inaccessible because:

  • Kotlin compiles Companion as a static nested class with a Companion field
  • Xamarin bindings don't expose these factory methods directly
  • CreateUnitViaCompanion() in JavaReflectionHelper.cs:130-178 is the only way to create these unit objects for write operations
  1. No Direct Property Access for Read Operations

When reading values like weight or calories, the SDK returns Mass or Energy objects. To extract the actual double value:

  • mass.InKilograms → Not available in bindings
  • energy.InKilocalories → Not available in bindings

The extraction methods (ExtractMassValue, ExtractEnergyValue, etc.) must use reflection fallbacks:

  1. TryOfficialUnitsApi() - calls inUnit() method with unit constant

  2. TryGetPropertyValue() - accesses field via reflection

  3. TryCallMethod() - invokes getter method via reflection

  4. TryParseFromString() - last resort: parse from toString() output

  5. Kotlin/Java Interop Mismatch

Kotlin properties compile to Java getter methods with specific naming:

  • Kotlin val inKilograms: Double → Java getInKilograms() or just inKilograms()
  • The Xamarin binding generator may not recognize these patterns correctly
  1. Unit Constants Not Exposed

TryGetUnitConstant() in JavaReflectionHelper.cs:180-217 accesses static fields like Mass.KILOGRAMS which are unit constants needed for
the inUnit() API - these are also not directly accessible through bindings.

When Can Reflection Be Removed?

Reflection can potentially be removed when:

  1. Xamarin.AndroidX.Health.Connect.ConnectClient reaches stable release with complete bindings
  2. Microsoft improves the Java/Kotlin binding generator to handle Companion objects and Kotlin properties
  3. Google provides a C#-friendly API layer (unlikely)

Summary

Operation Why Reflection Needed
Read weight/height/calories Unit value extraction (InKilograms, InCalories) not bound
Write weight/height/calories Kotlin Companion factory methods (Mass.kilograms()) not bound
Unit constants Static fields (Mass.KILOGRAMS) not exposed

The reflection is a necessary workaround for Xamarin binding limitations, not a design choice. The battle-tested multiple-fallback
approach ensures the code works across different Android versions and binding behaviors.

@Kebechet Kebechet mentioned this pull request Dec 4, 2025
@jmichas
Copy link
Copy Markdown

jmichas commented Dec 17, 2025

I just wanted to add a note in case you all weren't aware.
The DataOrigin on Android is not writeable.
You can set it and send it but Android will always overwrite it with the package name of the app that is writing the data. I just ran a test trying to write "com.fitbit.FitbitMobile" in an attempt to spoof steps from a fitbit device but the origin when read back out was my app's package name that inserted the data.

Not sure if this at all affects your planned changes. I haven't reviewed all the work that you all have done.

@Kebechet
Copy link
Copy Markdown
Owner

@jmichas thanks for the heads-up

@Kebechet Kebechet merged commit 99cdeb0 into Kebechet:main Dec 22, 2025
@Kebechet Kebechet mentioned this pull request Dec 22, 2025
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants