Skip to Content

Android

Native Android toolkit that integrates the Zing Fitness experience into your app. The SDK ships as an AAR (coach.zing:fitness-sdk) consumable via GitHub Packages.

Requirements

RequirementValue / Notes
Minimum Android version8.0 (API 26)
Compile SDK34+
Kotlin2.1.0
Dependency injectionHilt (com.google.dagger:hilt-android)
Maven credentialsGitHub Packages PAT with read:packages

Setup

Add the GitHub Packages Repository

Add the following to your settings.gradle or top-level build.gradle:

// settings.gradle or top-level build.gradle dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url = uri("https://maven.pkg.github.com/Muze-Fitness/fitness-coach-sdk-android") val localProperties = java.util.Properties() val file = File(rootDir, "local.properties") if (file.exists()) { localProperties.load(file.inputStream()) } credentials { username = localProperties.getProperty("sdk_maven_read_username") ?: System.getenv("GITHUB_USER") password = localProperties.getProperty("sdk_maven_read_token") ?: System.getenv("GITHUB_TOKEN") } } } }

Create local.properties next to your top-level settings.gradle if it does not exist yet and provide the credentials:

sdk_maven_read_username=GITHUB_USERNAME sdk_maven_read_token=ghp_xxx_with_read_packages

Declare the Dependency

dependencies { implementation("coach.zing:fitness-sdk:<latest-version>") }

Replace <latest-version> with the version published in GitHub Packages (e.g. 2.1.0).

Enable Hilt

Add the Hilt plugin and dependencies to your app-level build.gradle:

plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("com.google.dagger.hilt.android") kotlin("kapt") // or id("com.google.devtools.ksp") } dependencies { implementation("com.google.dagger:hilt-android:2.56.1") kapt("com.google.dagger:hilt-android-compiler:2.56.1") // ksp("com.google.dagger:hilt-android-compiler:2.56.1") }

Create an Application Subclass

Create an Application subclass that extends SdkApplication. The SDK must be initialized from your Application class — call ZingSdk.init() from onCreate():

@HiltAndroidApp class FitnessApp : SdkApplication() { private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) override fun onCreate() { super.onCreate() scope.launch { ZingSdk.init() } } }

Register it in AndroidManifest.xml:

<application android:name=".FitnessApp" ... />

Initialization & Authentication

The SDK follows a three-step lifecycle: init()login(sdkAuth)logout().

  1. init() — configure the SDK (theme, feature configuration). Call once, from your Application class.
  2. login(sdkAuth) — authenticate and start a session (must be called only when authState is SdkAuthState.LoggedOut).
  3. logout() — end the session and clear user data.

Authentication methods

MethodClassDescription
Partner KeySdkAuthentication.ApiKeyAPI key authentication. partnerUserId is optional and links the session to your own user id.
Partner TokenSdkAuthentication.ExternalTokenPass a JWT minted by your own backend.

For the backend requirements behind these two modes — the JWKS your server must publish for JWT auth, the required claims, and why the API key is the weaker option — see Authorization.

Login

suspend fun login(sdkAuth: SdkAuthentication)

Must be called after init() when authState is SdkAuthState.LoggedOut. Throws SdkAlreadyLoggedInException if the user is already logged in.

Partner Key — pass your API key directly:

ZingSdk.login(SdkAuthentication.ApiKey(apiKey = "your-api-key"))

Pass partnerUserId to link the session to your own user id. If omitted, the SDK generates an id for a new user:

ZingSdk.login( SdkAuthentication.ApiKey(apiKey = "your-api-key", partnerUserId = "your-user-id") )

Partner Token — pass a JWT minted by your own backend:

ZingSdk.login(SdkAuthentication.ExternalToken(jwtToken = yourAuthRepo.getToken()))

Auth state monitoring

Observe ZingSdk.authState: StateFlow<SdkAuthState> to react to authentication changes:

StateDescription
SdkAuthState.LoggedOutNo active session
SdkAuthState.InProgressLogin is in progress
SdkAuthState.LoggedInSession active. Carries the authenticated userId — for ApiKey this is partnerUserId (or the generated id, if omitted); for ExternalToken this is the sub claim of jwtToken.

Session errors

Set criticalErrorHandler to react when an active session can’t be refreshed (e.g. the refresh token was revoked server-side):

ZingSdk.criticalErrorHandler = CriticalErrorHandler { error -> // e.g. log out and prompt re-authentication }

Logout

suspend fun logout()

Ends the current session. Throws SdkAlreadyLoggedOutException if the user is already logged out.

Profile parameters

Update user profile fields directly, without going through SDK UI:

suspend fun setProfileParams(profileParams: ProfileParams)

Requires SdkAuthState.LoggedIn.

FieldTypeDescription
nameString?
genderUserGender?MALE, FEMALE, OTHER
heightFloat?Centimeters. Always pass metric, regardless of measurementSystem.
weightFloat?Kilograms. Always pass metric, regardless of measurementSystem.
ageInt?
measurementSystemMeasurementUnit?IMPERIAL, METRIC
ZingSdk.setProfileParams( ProfileParams( name = "Alex", gender = UserGender.MALE, height = 180f, weight = 75f, age = 30, measurementSystem = MeasurementUnit.METRIC, ) )

Full example

class FitnessApp : SdkApplication() { override fun onCreate() { super.onCreate() ZingSdk.init() } } // Start a session (e.g. in your Activity or ViewModel) fun onStart(scope: CoroutineScope) { scope.launch { if (ZingSdk.authState.value is SdkAuthState.LoggedOut) { ZingSdk.login(SdkAuthentication.ApiKey(apiKey = "your-api-key")) } } } // End the session fun onLogout(scope: CoroutineScope) { scope.launch { ZingSdk.logout() // e.g. navigate to login or clear user data } }

Health Connect

The SDK integrates with Health Connect to read and write activity data. The required Health Connect permissions are declared by the SDK itself and merged into your app — you do not need to add them manually:

android.permission.health.READ_STEPS android.permission.health.READ_HEART_RATE android.permission.health.READ_EXERCISE android.permission.health.READ_TOTAL_CALORIES_BURNED android.permission.health.WRITE_STEPS android.permission.health.WRITE_HEART_RATE android.permission.health.WRITE_EXERCISE android.permission.health.WRITE_TOTAL_CALORIES_BURNED

By default, Zing reads and writes Health Connect data while the app is in use, as soon as the user grants the runtime Health Connect permissions. No additional setup is required.

Background sync (optional)

You can additionally enable collecting Health Connect data in the background (e.g. after a reboot, without the app being open). This requires three changes:

1. Add the following permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

2. Declare the SDK’s background sync service and boot receiver inside <application>:

<service android:name="coach.zing.fitness.coach.service.ZingSdkHCForegroundService" android:exported="false" android:foregroundServiceType="health"> <intent-filter> <action android:name="coach.zing.fitness.sdk.HC_SYNC" /> </intent-filter> </service> <receiver android:name="coach.zing.fitness.coach.broadcast.SdkHealthSyncBootReceiver" android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>

3. Enable it via Configuration when initializing the SDK:

ZingSdk.init( configuration = Configuration( healthConnectBackgroundSync = true, ), )

Background sync is disabled by default (healthConnectBackgroundSync = false).

Theming

Working with themes

Use the theming playground to interactively preview how colors, typography, corner rounding, and images look in the SDK screens before writing any code.

Pass a ZingSdkTheme to ZingSdk.init() to customize the SDK’s appearance. Every field is optional — any unset field falls back to the SDK default.

ZingSdk.init( theme = ZingSdkTheme( colors = ZingSdkTheme.Colors( brandPrimary = 0xFF1A73E8, brandSecondary = 0xFF34A853, ), cornerRadius = ZingSdkTheme.CornerRadius( button = ZingSdkTheme.CornerRadius.SdkRadius.Pill, ), typography = ZingSdkTheme.Typography( brand = Typeface.createFromAsset(assets, "fonts/MyBrandFont.ttf"), system = Typeface.createFromAsset(assets, "fonts/MySystemFont.ttf"), ), assets = ZingSdkTheme.Assets( planBackground = R.drawable.my_plan_background, welcomePicture = R.drawable.my_welcome_picture, coachImages = ZingSdkTheme.Assets.CoachAsset( john = R.drawable.my_coach_john, jennifer = R.drawable.my_coach_jennifer, sarah = R.drawable.my_coach_sarah, chris = R.drawable.my_coach_chris, ), ), ), )
FieldTypeDescription
colorsZingSdkTheme.ColorsOverrides brand, text, button, and background colors. Values are Long in AARRGGBB format.
cornerRadiusZingSdkTheme.CornerRadiusOverrides button border radius. Use SdkRadius.Value(dp) for a fixed radius or SdkRadius.Pill for a pill shape.
typographyZingSdkTheme.TypographyOverrides font typefaces for brand and system text.
assetsZingSdkTheme.AssetsOverrides images for plan background, welcome screen, and coach portraits.

Working with typography

Pass Typeface objects directly to ZingSdkTheme.Typography.

FieldApplies toDefault
brandHeadings, display text, counter, coach nameSDK built-in (Outfit)
systemBody text, UI elements, coach chatSDK built-in (Roboto)

Both fields are optional — omitting a field keeps the SDK’s built-in font for that role.

Working with pictures

Pass drawable resource IDs directly to ZingSdkTheme.Assets. The SDK uses the IDs to load images from your app’s resources.

FieldUsed for
planBackgroundPlan section background image
welcomePictureWelcome screen illustration
coachImages.johnCoach John avatar
coachImages.jenniferCoach Jennifer avatar
coachImages.sarahCoach Sarah avatar
coachImages.chrisCoach Chris avatar

All fields are optional — omitting a field falls back to the SDK’s built-in image.

For best quality across device densities, provide density-specific variants. Android automatically picks the correct one:

res/ drawable-mdpi/my_welcome_picture.png drawable-hdpi/my_welcome_picture.png drawable-xhdpi/my_welcome_picture.png drawable-xxhdpi/my_welcome_picture.png drawable-xxxhdpi/my_welcome_picture.png

Launching Zing Screens

You can open any major Zing screen explicitly via ZingSdkActivity.launch(context, StartingRoute.<Destination>). Supported destinations include:

  • StartingRoute.Home
  • StartingRoute.CustomWorkout
  • StartingRoute.AiAssistant
  • StartingRoute.WorkoutPlanDetails
  • StartingRoute.FullSchedule
  • StartingRoute.ProfileSettings

Example

button.setOnClickListener { ZingSdkActivity.launch(this, StartingRoute.AiAssistant) }
Last updated on