Native
Android library for integrating WeFitter and Samsung Health into your app. If you want this native SDK, please contact WeFitter at support@wefitter.com. The React Native bridge is available on the public github pages.
Installation
Add wefitter-shealth-2.1.1.aar
and samsung-health-data-1.5.0.aar
to libs
folder which should normally be in app/libs
.
Add the following dependencies to your app/build.gradle
:
Hide code example
dependencies {
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.compose.material3:material3-android:1.2.1'
testImplementation 'junit:junit:4.13.2'
implementation 'androidx.work:work-runtime-ktx:2.9.0'
implementation 'androidx.lifecycle:lifecycle-service:2.8.3'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.activity:activity-compose:1.9.0'
implementation platform('androidx.compose:compose-bom:2024.06.00')
implementation files('libs/samsung-health-data-1.5.0.aar')
implementation project(path: ':wefitter-shealth')
}
Usage
Add the following to your MainActivity.kt
:
Breaking changes!!! Make sure you request android.Manifest.permission.ACTIVITY_RECOGNITION before you configure the WeFitter SDK, as without this permission the SDK will never connect!
Hide code example
import com.wefitter.shealth.WeFitterSHealth
import com.wefitter.shealth.WeFitterSHealthError
class MainActivity : AppCompatActivity() {
private lateinit var weFitterSHealth: WeFitterSHealth
private var isConfigured: Boolean = false
private var ACTIVITY_RECOGNITION: Boolean = false
private var POST_NOTIFICATIONS: Boolean = false
private val prefix = "com.samsung.health"
// Change the below set of app permissions to reflect your app's approved permissions by Samsung
// Only the below permissions will be asked to the user for approval
private val app_permissions = setOf(
"com.samsung.shealth.step_daily_trend",
"$prefix.heart_rate",
"$prefix.height",
"$prefix.weight",
"$prefix.sleep_stage",
"$prefix.exercise",
//"$prefix.blood_glucose",
//"$prefix.blood_pressure",
//"$prefix.body_fat",
//"$prefix.body_temperature",
//"$prefix.oxygen_saturation",
)
private val healthConnectPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
Log.i(TAG, "permissions $permissions")
when {
permissions.getOrDefault(android.Manifest.permission.ACTIVITY_RECOGNITION, false) -> {
ACTIVITY_RECOGNITION = true
if (isConfigured && !weFitterSHealth.isConnected()) {
weFitterSHealth.connect()
}
}
permissions.getOrDefault(android.Manifest.permission.POST_NOTIFICATIONS, false) -> {
POST_NOTIFICATIONS = true
}
else -> {
// No health connect access granted, service can't be started as it will crash
Toast.makeText(this, "Health permission is required!", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
healthConnectPermissionRequest.launch(
arrayOf(
android.Manifest.permission.ACTIVITY_RECOGNITION,
android.Manifest.permission.POST_NOTIFICATIONS))
// create instance of WeFitterSHealth
weFitterSHealth = WeFitterSHealth(this)
// create statusListener to receive status changes and errors - optional
val statusListener = object : WeFitterSHealth.StatusListener {
override fun onConfigured(configured: Boolean) {
Log.i(WeFitterSHealth.TAG, "configured: $configured")
// enable connection if it hasn't already been enabled,
// or move this for example to a button press or toggle change
// and then `weFitterSHealth.disconnect()` is also useful.
isConfigured = true
// if (configured && !weFitterSHealth.isConnected()) {
// weFitterSHealth.connect()
// }
}
override fun onConnected(connected: Boolean) {
Log.i(WeFitterSHealth.TAG, "connected: $connected")
}
override fun onError(error: WeFitterSHealthError) {
Log.e(WeFitterSHealth.TAG, "error: ${error.reason.message}")
// `resolvable` boolean indicates the error can be passed to `tryToResolveError` function
// `reason` can be checked to override specific messages
if (error.reason.resolvable) {
AlertDialog.Builder(this@MainActivity)
.setMessage(error.reason.message)
.setPositiveButton(android.R.string.ok) { _, _ ->
// `tryToResolveError` will guide the user on fixing certain errors
// for example:
// - link to the app store to install or update Samsung Health
// - open Samsung Health to accept privacy policy
// - open Settings when Samsung Health needs to be enabled
weFitterSHealth.tryToResolveError(error)
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
}
}
// customize notification - optional
val notificationConfig = WeFitterSHealth.NotificationConfig().apply {
// override fields
title = "CUSTOM_TITLE"
text = "CUSTOM_TEXT"
iconResourceId = R.mipmap.ic_notification // pass custom icon resource id
channelId = "CUSTOM_CHANNEL_ID"
channelName = "CUSTOM_CHANNEL_NAME"
}
// configure WeFitterSHealth
// token should be jwt and contain an id corresponding to a WeFitter profile
// api url should be base without v1.3/ingest/ as the library will append this
// for example: https://api.wefitter.com/api/
weFitterSHealth.configure("YOUR_TOKEN", "YOUR_API_URL", statusListener, notificationConfig, appPermissions = app_permissions)
}
companion object {
const val TAG = "MainActivity"
}
}
