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 except WorkoutPlanCard |
Requirements
| Requirement | Value / Notes |
|---|---|
| Flutter | 3.3.0+ |
| Android minSdk | 26 (Android 8.0) |
| Android compileSdk | 34+ |
| 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.gitThen 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>Health Connect (optional)
If you enable Health Connect synchronization, add the following permissions:
<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.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />To restart health sync after reboot, register the boot receiver inside <application>:
<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>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(
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(
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) |
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.