Production-grade architecture for embedding a Flutter SDK in a native Android application with dynamic white-label theming support.
+---------------------------+ +---------------------------+
| Native Android App | | Flutter SDK |
+---------------------------+ +---------------------------+
| | | |
| WhiteLabelThemeManager |<--->| ThemeController |
| (StateFlow) | | (ChangeNotifier) |
| | | |
| FlutterSdkIntegration |<--->| SdkPlatformChannel |
| (Facade) | | (MethodChannel Bridge) |
| | | |
| WhiteLabelComposeTheme | | WhiteLabelThemeProvider |
| (Compose Theme) | | (InheritedWidget) |
| | | |
+---------------------------+ +---------------------------+
| |
v v
+---------------------------+ +---------------------------+
| Native Compose UI | | Flutter SDK UI |
| (Same theme tokens) | | (Same theme tokens) |
+---------------------------+ +---------------------------+
- Single Source of Truth: Both native and Flutter UI consume the same
WhiteLabelThememodel - Hot-Swappable Theme: Theme can be changed at runtime without app restart
- Dark Mode Support: Automatic dark mode handling with separate color tokens
- Native-Driven Navigation: Flutter navigation controlled via MethodChannel
- Deep Link Support: Deep links forwarded from native to Flutter
- Event Bridge: Bidirectional event communication between native and Flutter
- iOS Ready: Architecture designed for cross-platform compatibility
Android_Flutter_Sdk_intg/
├── app/ # Native Android App
│ └── src/main/java/com/example/android_flutter_sdk_intg/
│ ├── domain/
│ │ ├── model/
│ │ │ ├── WhiteLabelTheme.kt # Theme domain model
│ │ │ └── NavigationCommand.kt # Navigation commands
│ │ └── theme/
│ │ ├── ThemeExtractor.kt # Extract theme from Android
│ │ └── WhiteLabelThemeManager.kt # Theme state management
│ ├── flutter/
│ │ ├── FlutterEngineManager.kt # Engine lifecycle
│ │ ├── FlutterSdkBridge.kt # MethodChannel bridge
│ │ └── FlutterSdkIntegration.kt # High-level SDK API
│ ├── ui/
│ │ ├── screens/
│ │ │ └── NativeHomeScreen.kt # Sample native screen
│ │ └── theme/
│ │ └── WhiteLabelComposeTheme.kt # Compose theme wrapper
│ ├── MainActivity.kt # Main entry point
│ ├── FlutterSdkActivity.kt # Flutter host activity
│ └── SdkApplication.kt # Application class
│
├── flutter_sdk_module/ # Flutter SDK Module
│ └── lib/
│ ├── main.dart # Entry point
│ ├── flutter_sdk_module.dart # Public API exports
│ └── src/
│ ├── sdk.dart # SDK facade
│ ├── core/
│ │ ├── theme/
│ │ │ └── theme_controller.dart
│ │ └── navigation/
│ │ └── navigation_controller.dart
│ ├── domain/
│ │ └── models/
│ │ ├── white_label_theme.dart
│ │ └── navigation_command.dart
│ ├── platform/
│ │ └── sdk_platform_channel.dart
│ └── presentation/
│ ├── widgets/
│ │ └── sdk_root_widget.dart
│ └── screens/
│ ├── sdk_home_screen.dart
│ ├── sdk_details_screen.dart
│ └── sdk_settings_screen.dart
│
└── scripts/
├── build_flutter_aar.ps1 # Windows build script
└── build_flutter_aar.sh # Unix build script
- Android Studio Arctic Fox or later
- Flutter SDK 3.9.0 or later
- Kotlin 2.0+
- Gradle 8.7+
# Navigate to Flutter module
cd flutter_sdk_module
# Get dependencies
flutter pub get
# Build AAR (creates debug, profile, and release variants)
flutter build aar --no-tree-shake-iconsThe Gradle configuration is already set up. After building the AAR:
- The AAR artifacts will be in
flutter_sdk_module/build/host/outputs/repo/ - The
settings.gradle.ktsalready includes the Maven repository - The
app/build.gradle.ktsalready includes the dependencies
# From project root
./gradlew :app:installDebug// Get the integration instance
val integration = FlutterSdkIntegration.getInstance()
// Create a custom theme
val theme = ThemeExtractor.createEnterpriseTheme(
clientId = "client_abc",
themeName = "Client ABC Brand",
primaryColor = 0xFF1976D2,
secondaryColor = 0xFF26A69A,
isDarkMode = false
)
// Update theme (automatically propagates to Flutter)
integration.updateTheme(theme)// Open Flutter SDK at home
startActivity(FlutterSdkActivity.createIntent(this))
// Navigate to specific route
integration.navigateTo("/details", mapOf("id" to "123"))
startActivity(FlutterSdkActivity.createIntent(this))// In MainActivity.onCreate or onNewIntent
val uri = intent.data
if (uri != null) {
integration.handleDeepLink(
uri = uri.toString(),
parameters = mapOf("source" to "deep_link"),
source = "external"
)
startActivity(FlutterSdkActivity.createIntent(this))
}// When notification is received
integration.handleNotification(mapOf(
"type" to "promo",
"title" to "Special Offer",
"route" to "/details"
))The theme contract defines the structure for cross-platform theming:
data class WhiteLabelTheme(
val version: String, // Contract version
val clientId: String, // Client identifier
val themeName: String, // Display name
val isDarkMode: Boolean, // Dark mode flag
val lightColors: ColorTokens, // Light mode colors
val darkColors: ColorTokens, // Dark mode colors
val typography: TypographyTokens,
val spacing: SpacingTokens,
val borderRadius: BorderRadiusTokens
)All colors use ARGB Long format (e.g., 0xFF1976D2) for cross-platform compatibility.
| Token | Description |
|---|---|
| primary | Primary brand color |
| onPrimary | Text/icon color on primary |
| primaryContainer | Container using primary |
| secondary | Secondary brand color |
| tertiary | Tertiary accent color |
| error | Error state color |
| surface | Surface/card background |
| background | Screen background |
| outline | Border/divider color |
Material Design 3 typography scale:
- displayLarge, displayMedium, displaySmall
- headlineLarge, headlineMedium, headlineSmall
- titleLarge, titleMedium, titleSmall
- bodyLarge, bodyMedium, bodySmall
- labelLarge, labelMedium, labelSmall
| Token | Default Value |
|---|---|
| xxs | 2dp |
| xs | 4dp |
| sm | 8dp |
| md | 16dp |
| lg | 24dp |
| xl | 32dp |
| xxl | 48dp |
| Method | Direction | Description |
|---|---|---|
| updateTheme | Native -> Flutter | Push new theme |
| setDarkMode | Native -> Flutter | Set dark mode |
| getTheme | Native <- Flutter | Get current theme |
| requestTheme | Flutter -> Native | Request theme from native |
| Method | Direction | Description |
|---|---|---|
| navigate | Native -> Flutter | Execute navigation command |
| handleDeepLink | Native -> Flutter | Handle deep link |
| getCurrentRoute | Native <- Flutter | Get current route |
| Method | Direction | Description |
|---|---|---|
| onSdkEvent | Flutter -> Native | SDK event (analytics, errors) |
| onNavigationStateChanged | Flutter -> Native | Navigation state update |
| Method | Direction | Description |
|---|---|---|
| onNotificationReceived | Native -> Flutter | Forward notification |
| onCustomEvent | Native -> Flutter | Custom event |
| onAppStateChanged | Native -> Flutter | App lifecycle state |
The architecture is designed for iOS compatibility:
- Platform-Agnostic Models: All theme models use primitive types (Long for colors, Double for dimensions)
- Versioned Contracts: MethodChannel names include version for backward compatibility
- No Android-Specific Types: Domain models don't use Android Color, Drawable, etc.
- Single Entry Point: Flutter module has one main entry point
To implement iOS:
- Create Swift equivalents of
WhiteLabelThemeand related models - Implement
FlutterSdkBridgeusing FlutterMethodChannel - Create
FlutterSdkIntegrationfacade - Use same MethodChannel names and contract
- Always use theme tokens, never hardcode colors
- Access colors via
context.colorsextension in Flutter - Use
WhiteLabelComposeThemewrapper in Compose - Test both light and dark modes
- Define all routes in
_getRoutes()in main.dart - Use
SdkScreenMixinfor automatic analytics tracking - Handle back navigation via
navigationController.pop()
- Use
Sdk.instance.trackError()for error reporting - Handle MethodChannel errors gracefully
- Provide fallback themes for initialization failures
Proprietary - Internal Use Only