Flutter
Flutter plugin that wires the native Zing SDK on Android and iOS (and provides a Dart-facing API for initialization, logout, and launching native screens).
Current platform support
The Flutter plugin currently supports Android and iOS.
| Platform | Status | Notes |
|---|---|---|
| Android | Fully Supported | All features |
| iOS | Fully Supported | All features |
Requirements
| Requirement | Value / Notes |
|---|---|
| Flutter | 3.3.0+ |
| Android minSdk | 26 (Android 8.0) |
| Android compileSdk | 36+ |
| Dependency injection (Android) | Hilt |
| Maven credentials (Android native SDK) | GitHub Packages token |
| iOS minimum version | 16.0 |
Install the plugin
Add the Git dependency to your pubspec.yaml (the plugin is distributed privately and is not published on pub.dev):
dependencies:
zing_sdk_initializer:
git:
url: https://github.com/Muze-Fitness/fitness-coach-sdk-flutter.git
ref: v1.0.0Check the GitHub releases page for the latest available version.
Then run flutter pub get.
Android setup
To integrate on Android, you must configure your project to support the native Zing SDK dependencies (Hilt + GitHub Packages).
Add Maven repository & credentials
Add the GitHub Packages repository to your Android build (project-level android/build.gradle or settings.gradle):
maven {
url = uri("https://maven.pkg.github.com/Muze-Fitness/fitness-coach-sdk-android")
val localProperties = java.util.Properties()
val localPropertiesFile = File(rootDir, "local.properties")
if (localPropertiesFile.exists()) {
localProperties.load(localPropertiesFile.inputStream())
}
credentials {
username = localProperties.getProperty("zing_sdk_username")
password = localProperties.getProperty("zing_sdk_token")
}
}Ensure your local.properties contains your credentials:
zing_sdk_username=GITHUB_USERNAME
zing_sdk_token=ghp_xxx_with_read_packagesConfigure Hilt (KSP or KAPT)
The native SDK uses Hilt for dependency injection.
- Option A: KSP (recommended)
// Project-level (android/build.gradle or settings.gradle)
id("com.google.dagger.hilt.android") version "2.56.1" apply false
id("com.google.devtools.ksp") version "2.1.20-2.0.0" apply false// App module (android/app/build.gradle)
plugins {
id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.56.1")
ksp("com.google.dagger:hilt-android-compiler:2.56.1")
}- Option B: KAPT (legacy projects)
// Project-level (android/build.gradle or settings.gradle)
id("com.google.dagger.hilt.android") version "2.56.1" apply false// App module (android/app/build.gradle)
plugins {
kotlin("kapt")
id("com.google.dagger.hilt.android")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.56.1")
kapt("com.google.dagger:hilt-android-compiler:2.56.1")
}Custom Application class
Create an Application class extending SdkApplication and annotate it with @HiltAndroidApp:
import coach.zing.fitness.coach.SdkApplication
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MyApplication : SdkApplication()Register it in AndroidManifest.xml:
<application
android:name=".MyApplication"
... >Update MainActivity
Change MainActivity to inherit from FlutterFragmentActivity and add @AndroidEntryPoint:
import dagger.hilt.android.AndroidEntryPoint
import io.flutter.embedding.android.FlutterFragmentActivity
@AndroidEntryPoint
class MainActivity : FlutterFragmentActivity()Disable the default WorkManager initializer
Add the following provider override inside <application> in AndroidManifest.xml:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>Initialization
Initialize the SDK from Dart during app startup. You need to provide an authentication configuration during initialization.
API Key
Use this mode when backend integration is not available:
import 'package:zing_sdk_initializer/zing_sdk_initializer.dart';
await ZingSdk.instance.init(
authentication: SdkAuthentication.apiKey(
ios: 'your-ios-api-key',
android: 'your-android-api-key',
),
);External Token
Use this mode when your backend manages user authentication and issues JWT tokens.
import 'package:zing_sdk_initializer/zing_sdk_initializer.dart';
await ZingSdk.instance.init(
authentication: SdkAuthentication.externalToken(yourTokenCallback),
);Implement the AuthTokenCallback interface.
abstract interface class AuthTokenCallback {
/// Called when SDK needs an authentication token
/// Return a valid JWT containing a `sub` claim with the partner user ID.
Future<String> getAuthToken();
/// Called when the current token is no longer valid.
void onTokenInvalid();
}Initialization errors
| Code | Description |
|---|---|
already_initialized | Called init() more than once |
native_init_failed | Native SDK failed to initialize (invalid auth config or internal error) |
Configuration
Pass an SdkConfiguration to customize SDK behavior:
await ZingSdk.instance.init(
authentication: ...,
configuration: SdkConfiguration(
coachesAvailability: CoachesAvailability.userGenderBased,
genderAvailability: GenderAvailability.binary,
),
);| Field | Type | Default | Description |
|---|---|---|---|
coachesAvailability | CoachesAvailability | allCoaches | allCoaches — all coaches are shown; userGenderBased — only coaches matching the user’s gender. |
genderAvailability | GenderAvailability | all | all — all gender options; binary — male/female only. |
Theme
Pass an SdkTheme to apply branding overrides. Any unset field falls back to SDK defaults.
await ZingSdk.instance.init(
authentication: ...,
theme: SdkTheme(
colors: SdkColors(
brandPrimary: Color(0xFF1A73E8),
brandSecondary: Color(0xFF34A853),
),
cornersRounding: SdkCornerRounding(
buttonBorder: SdkRadius.pill(),
),
typography: SdkTypography(
brand: 'YourBrandFont',
system: 'YourSystemFont',
),
),
);| Field | Type | Description |
|---|---|---|
colors | SdkColors | Overrides brand, text, button and background colors. |
cornersRounding | SdkCornerRounding | Overrides button border radius. Use SdkRadius.value(n) for a fixed radius or SdkRadius.pill() for a pill shape. |
typography | SdkTypography | Overrides font families for brand and system text. |
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 fully composed SdkTheme to customize all visual aspects of the SDK. Every field is optional — any unset field falls back to the SDK default.
await ZingSdk.instance.init(
authentication: ...,
theme: SdkTheme(
colors: SdkColors(
brandPrimary: Color(0xFF1A73E8),
brandSecondary: Color(0xFF34A853),
textHeadingDarkPrimary: Color(0xFF1D212C),
textHeadingLightPrimary: Color(0xFFFFFFFF),
textBodyDarkPrimary: Color(0xFF1D212C),
textBodyDarkSecondary: Color(0xFF6B7280),
buttonPrimary: Color(0xFF1A73E8),
buttonSecondary: Color(0xFF34A853),
bgPrimary: Color(0xFFFFFFFF),
bgSecondary: Color(0xFFF3F4F6),
),
cornersRounding: SdkCornerRounding(
buttonBorder: SdkRadius.pill(),
),
typography: SdkTypography(
brand: 'YourBrandFont',
system: 'YourSystemFont',
),
),
);Working with pictures
The SDK automatically loads custom images from the host app’s platform resources using fixed asset names. No Flutter-level code is required — just add the images with the correct names to your platform project.
Android
Add drawable files to android/app/src/main/res/drawable/. For best quality, provide density-specific variants — Android will automatically pick the correct one for the device screen:
res/
drawable-mdpi/zing_welcome_picture.png
drawable-hdpi/zing_welcome_picture.png
drawable-xhdpi/zing_welcome_picture.png
drawable-xxhdpi/zing_welcome_picture.png
drawable-xxxhdpi/zing_welcome_picture.png| Drawable name | Used for |
|---|---|
zing_plan_background | Plan section background image |
zing_welcome_picture | Welcome screen illustration |
zing_coach_john | Coach John avatar |
zing_coach_jennifer | Coach Jennifer avatar |
zing_coach_sarah | Coach Sarah avatar |
zing_coach_chris | Coach Chris avatar |
iOS
Add image assets to Assets.xcassets using the same names:
| Asset name | Used for |
|---|---|
zing_plan_background | Plan section background image |
zing_welcome_picture | Welcome screen illustration |
zing_coach_john | Coach John avatar |
zing_coach_jennifer | Coach Jennifer avatar |
zing_coach_sarah | Coach Sarah avatar |
zing_coach_chris | Coach Chris avatar |
zing_coach_manel | Coach Manel avatar |
zing_coach_adriana | Coach Adriana avatar |
All image names are optional — the SDK falls back to its built-in assets for any name that is not found.
Working with typography
Pass SdkTypography inside SdkTheme to override the SDK’s built-in fonts. Two font roles are available:
| Field | Applies to | Default |
|---|---|---|
brand | Headings, display text, counter, coach name | SDK built-in (Outfit) |
system | Body text, UI elements, coach chat | SDK built-in (SF Pro / Roboto) |
Both fields are optional — omitting a field keeps the SDK’s built-in font for that role.
The value must be the name the font is registered under in the host app’s platform resources. Register your font first, then pass the same name to SdkTypography:
| Platform | How to register | Name to pass |
|---|---|---|
| Android | Place .ttf/.otf in android/app/src/main/res/font/ | Filename without extension (e.g. "inter") |
| iOS | Add the font file to Xcode and declare it under UIAppFonts in Info.plist | PostScript family name (e.g. "Inter") |
await ZingSdk.instance.init(
SdkAuthentication.apiKey(
ios: 'your-ios-api-key',
android: 'your-android-api-key',
),
theme: SdkTheme(
typography: SdkTypography(
brand: 'MyBrandFont', // registered as res/font/mybrandfont.ttf on Android
system: 'MySystemFont', // registered as PostScript name on iOS
),
),
);Login
After initialization, call login() to authenticate the user and start a session:
await ZingSdk.instance.login();Call login() only on the first session, when the auth state is SdkAuthStateLoggedOut. On subsequent sessions, init() automatically restores the previous session — you do not need to call login() again.
Login errors
| Code | Description |
|---|---|
not_initialized | SDK has not been initialized yet |
login_failed | Login failed (already logged in, login already in progress, or token retrieval failed) |
Logout
Logout and clear the user session.
await ZingSdk.instance.logout();Logout errors
| Code | Description |
|---|---|
not_initialized | SDK has not been initialized yet |
logout_failed | Logout failed (no active session) |
Auth State
Monitor authentication state changes via the authState stream:
ZingSdk.instance.authState.listen((state) {
switch (state) {
case SdkAuthStateLoggedOut():
// User is not authenticated
case SdkAuthStateInProgress():
// Authentication is in progress
case SdkAuthStateAuthenticated():
// User is authenticated
}
});Launch native screens
await ZingSdk.instance.openScreen(AiAssistantRoute());Supported routes:
HomeRoute()CustomWorkoutRoute()AiAssistantRoute()WorkoutPlanDetailsRoute()FullScheduleRoute()ProfileSettingsRoute()
Launch screen errors
| Code | Description |
|---|---|
not_initialized | SDK has not been initialized yet |
missing_route | No route argument provided |
unknown_route | Unrecognized route identifier |
no_activity | No activity or root view controller available to present the screen |
launch_failed | Screen launch failed |
Notes
- Configure auth/tokens as described in Authorization before launching UI.