This guide covers adding the Sonar Android SDK to your Kotlin app. The SDK supports two data sources through a single interface: Health Connect (Google's unified health API, available on all Android devices) and Samsung Health (Samsung devices only).
Requirements
| Android | API 28+ (minSdk 28) |
| Kotlin | 1.8+ |
| Sonar account | With an API key (sign up here) |
| Health Connect | Health Connect app installed on the device |
| Samsung Health | Approval via Sonar support (Samsung devices only) |
Two Data Sources, One SDK
Both sources use the same SDK, the same initialization, and the same data methods. The differences are in setup and available metrics.
| Health Connect | Samsung Health | |
|---|---|---|
| Availability | All Android devices with Health Connect app | Samsung devices with Samsung Health app |
| Approval | Google Play Health Connect API review | Contact Sonar support |
| Metric coverage | ~30 metrics (broadest Android coverage) | ~25 metrics |
| Unique data | VO2 max, mindfulness, respiratory rate | Skin temperature |
Install the SDK
Add the dependency to your module-level build.gradle.kts:
dependencies {
implementation("co.sonar:sonar-android:1.+")
}
Sync your project with Gradle files.
Configure Permissions
Health Connect
1. Declare Permissions
Add the data types you need to your AndroidManifest.xml:
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
<uses-permission android:name="android.permission.health.READ_SLEEP" />
<uses-permission android:name="android.permission.health.READ_EXERCISE" />
<uses-permission android:name="android.permission.health.READ_DISTANCE" />
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.READ_WEIGHT" />
<uses-permission android:name="android.permission.health.READ_HEIGHT" />
2. Add Privacy Policy Activity
Health Connect requires your app to declare a privacy policy activity:
<activity
android:name=".PrivacyPolicyActivity"
android:exported="true">
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>
</activity>
3. Apply for Production Access
Samsung Health
Samsung Health requires a separate approval process:
- Contact Sonar support to submit a Samsung Health access request
- Once approved, Samsung Health data is available through the same SDK interface
- No additional manifest changes are needed
Integration Lifecycle
The SDK follows the same lifecycle as the iOS SDK: initialize, connect, sync, disconnect.
Step 1 — Initialize the SDK
Create the SDK instance in your Activity.onCreate() or Application.onCreate(). Initialization is asynchronous — wait for the callback before using the manager.
import co.sonar.sdk.Sonar
import co.sonar.sdk.SonarManager
class MainActivity : AppCompatActivity() {
private var sonar: SonarManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val token = fetchTokenFromBackend() // Your backend generates this
Sonar.initialize(
token = token,
context = this
) { manager, error ->
error?.let {
Log.e("Sonar", "Init failed: ${it.message}")
return@initialize
}
sonar = manager
}
}
}
Step 2 — Connect a User
Once initialized, connect the user to a health data source. This triggers the system permission dialog.
// Health Connect
sonar?.connect(
source = Source.HEALTH_CONNECT,
permissions = setOf(), // Empty = request all available types
backgroundSync = true,
context = this
) { success, error ->
if (success) {
Log.d("Sonar", "Connected to Health Connect")
} else {
Log.e("Sonar", "Failed: ${error?.message}")
}
}
// Samsung Health
sonar?.connect(
source = Source.SAMSUNG_HEALTH,
permissions = setOf(),
backgroundSync = true,
context = this
) { success, error ->
if (success) {
Log.d("Sonar", "Connected to Samsung Health")
} else {
Log.e("Sonar", "Failed: ${error?.message}")
}
}
Step 3 — Validate Connection
Check whether a connection is active before taking actions that depend on it:
// Check Health Connect
val hcUserId = sonar?.getUserId(source = Source.HEALTH_CONNECT)
// Check Samsung Health
val shUserId = sonar?.getUserId(source = Source.SAMSUNG_HEALTH)
if (hcUserId != null) {
Log.d("Sonar", "Health Connect connected: $hcUserId")
}
if (shUserId != null) {
Log.d("Sonar", "Samsung Health connected: $shUserId")
}
Disconnect
To stop syncing from the client side:
// Disconnect Health Connect
sonar?.disconnect(source = Source.HEALTH_CONNECT) { success ->
Log.d("Sonar", "Disconnected: $success")
}
// Disconnect Samsung Health
sonar?.disconnect(source = Source.SAMSUNG_HEALTH) { success ->
Log.d("Sonar", "Disconnected: $success")
}
This stops scheduled syncs and removes local connection state. Historical data remains available in the Sonar platform through the REST API.
Full Example
A minimal MainActivity.kt showing the complete Health Connect flow:
class MainActivity : AppCompatActivity() {
private var sonar: SonarManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initialize()
}
override fun onResume() {
super.onResume()
initialize() // Re-init on every foreground
}
private fun initialize() {
val token = fetchTokenFromBackend()
Sonar.initialize(token = token, context = this) { manager, error ->
error?.let {
Log.e("Sonar", "Init failed: ${it.message}")
return@initialize
}
sonar = manager
// Check for existing connection
val userId = manager?.getUserId(source = Source.HEALTH_CONNECT)
if (userId != null) {
Log.d("Sonar", "Already connected: $userId")
} else {
connect()
}
}
}
private fun connect() {
sonar?.connect(
source = Source.HEALTH_CONNECT,
permissions = setOf(),
backgroundSync = true,
context = this
) { success, error ->
if (success) {
Log.d("Sonar", "Connected to Health Connect")
} else {
Log.e("Sonar", "Connection failed: ${error?.message}")
}
}
}
private fun fetchTokenFromBackend(): String {
// Call your backend to generate a mobile token
// See the Authentication Flow section in the SDK overview
return "token_from_your_backend"
}
}
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Permission dialog doesn't appear | Health Connect app not installed | Prompt user to install Health Connect from the Play Store |
getUserId() returns null |
SDK not initialized or connection expired | Re-initialize with a fresh token and call connect() |
| Samsung Health not available | Approval pending or app not installed | Verify Samsung Health app is installed and Sonar support has approved access |
| Data appears incomplete | User denied some permissions | Guide user to Settings > Health Connect to check permissions |
| Build fails with dependency error | minSdk too low | Verify minSdk is 28+ in your build.gradle.kts |
| Google Play rejection | Missing Health Connect API approval | Apply through the Google Play Console — start early, reviews take weeks |
Go Deeper
- Mobile SDK Overview — Architecture, auth flow, and choosing the right SDK
- Data Catalog — Full metric reference with Health Connect and Samsung Health availability
- Data Delivery — Get notified when synced data is ready
- Authentication — Mobile token lifecycle and API key management
Sonar