From 4c5023a8316c09d95b487664d1a615eaafcf6d49 Mon Sep 17 00:00:00 2001 From: ChauVanSang Date: Mon, 8 Dec 2025 22:38:26 +0700 Subject: [PATCH] Update readme document --- README.md | 449 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 447 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa1ec9c..341cc03 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,447 @@ -# sample_hydrid_android -An example demonstrating how to integrate Flutter (following Clean Architecture) with native Android (using the MVVM pattern), including the mechanism for exchanging data between the two layers. +# Hybrid Android-Flutter Application + +A production-ready hybrid mobile application demonstrating seamless integration between native Android (Kotlin + Jetpack Compose) and Flutter Module with bidirectional communication. + +## Overview + +This project showcases how to build a hybrid mobile application where: +- Native Android screens are built with **Jetpack Compose** and **MVVM architecture** +- Flutter screens follow **Clean Architecture** with **BLoC pattern** +- Both layers communicate bidirectionally via **Platform Channels** +- Shared **FlutterEngine** for optimal performance +- Complete **CI/CD** pipeline with GitHub Actions and CircleCI + +## Features + +- **Hybrid Navigation**: Seamless transitions between native and Flutter screens +- **Bidirectional Communication**: Native ↔ Flutter event exchange via MethodChannel +- **Appliance Management**: Browse appliances in native UI, view details in Flutter +- **State Management**: + - Android: MVVM with StateFlow/SharedFlow + - Flutter: BLoC pattern with Freezed +- **Dependency Injection**: + - Android: Dagger Hilt + - Flutter: GetIt +- **Testing**: Comprehensive unit tests for Flutter BLoC components +- **CI/CD**: Automated builds and testing with GitHub Actions & CircleCI + +## Tech Stack + +### Android Native +- **Language**: Kotlin +- **UI**: Jetpack Compose +- **Architecture**: MVVM (Model-View-ViewModel) +- **DI**: Dagger Hilt +- **Networking**: Retrofit + OkHttp +- **Async**: Coroutines + Flow +- **Build**: Gradle with Kotlin DSL + +### Flutter Module +- **Language**: Dart +- **Architecture**: Clean Architecture with BLoC +- **State Management**: flutter_bloc + Freezed +- **DI**: GetIt +- **Networking**: Dio +- **Testing**: mockito + bloc_test +- **Code Generation**: build_runner, freezed + +### Communication Layer +- **Platform Channels**: MethodChannel for bidirectional method invocation +- **Event Channel**: EventChannel for streaming (setup for future use) +- **Data Format**: JSON for cross-platform data serialization + +## Architecture + +### High-Level Architecture + +``` +┌──────────────────────────────────────────────────────┐ +│ Android Native Layer │ +│ ┌────────────────────────────────────────────────┐ │ +│ │ DashboardActivity (Jetpack Compose) │ │ +│ │ - Appliance list │ │ +│ │ - Image carousel │ │ +│ │ - Support cards │ │ +│ └────────────────────────────────────────────────┘ │ +│ │ Intent │ +│ ▼ │ +│ ┌────────────────────────────────────────────────┐ │ +│ │ HybridFlutterActivity │ │ +│ │ - Hosts FlutterFragment │ │ +│ │ - Manages lifecycle │ │ +│ └────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────┘ + │ + │ MethodChannel + ▼ +┌──────────────────────────────────────────────────────┐ +│ Flutter Module Layer │ +│ ┌────────────────────────────────────────────────┐ │ +│ │ HomePage │ │ +│ │ - Flutter home screen │ │ +│ └────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────────────────────────────────┐ │ +│ │ ApplianceDetailPage │ │ +│ │ - Appliance details │ │ +│ │ - Interactive controls │ │ +│ └────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────┘ +``` + +### Communication Flow + +``` +Android Native Platform Channel Flutter +───────────── ───────────────── ─────── +DashBoardViewModel + │ + │ 1. Start HybridFlutterActivity + ├──────────────────────────────────────────────> + │ + │ 2. Send "navigate" event + │ + appliance data + ├────────────────────────> MethodChannel + │ │ + │ │ 3. Receive event + │ └────────────────> HybridBloc + │ │ + │ │ 4. Navigate + │ │ to route + │ ▼ + │ ApplianceDetailPage + │ │ + │ 5. Send "navigateBack" │ + │ <────────────────────────┤ + │ 6. Receive event │ + │<─────────────────────────┤ + │ + │ 7. Close activity + │ finish() +``` + +## Project Structure + +``` +sample_hydrid_android/ +├── app/ # Android native app +│ ├── src/main/java/com/example/myapplication/ +│ │ ├── core/ +│ │ │ ├── MainApplication.kt +│ │ │ ├── service/ +│ │ │ │ ├── HybridEventBus.kt # Event communication +│ │ │ │ └── HydridNavigateService.kt +│ │ │ ├── theme/ # Compose theme +│ │ │ └── utils/ +│ │ ├── data/ +│ │ │ ├── model/ # Data models +│ │ │ ├── remote/ # API service +│ │ │ └── repository/ +│ │ ├── di/ # Dagger Hilt modules +│ │ │ ├── FlutterEngineModule.kt +│ │ │ ├── NetworkModule.kt +│ │ │ └── ServiceModule.kt +│ │ └── ui/ +│ │ ├── components/ # Reusable Compose components +│ │ └── feature/ +│ │ ├── dashboard/ # Native dashboard +│ │ └── hydrid/ # Flutter host activity +│ └── build.gradle.kts +│ +├── flutter_module/ # Flutter module +│ ├── lib/ +│ │ ├── core/ +│ │ │ ├── di/ +│ │ │ │ └── injection_container.dart +│ │ │ ├── routes/ +│ │ │ │ ├── app_routes.dart +│ │ │ │ └── route_mapper.dart +│ │ │ ├── services/ +│ │ │ │ ├── hybrid_bus_service.dart +│ │ │ │ └── navigation_service.dart +│ │ │ └── theme/ +│ │ ├── data/ # Data layer +│ │ ├── domain/ # Domain layer +│ │ │ ├── api/ +│ │ │ ├── model/ +│ │ │ └── usecases/ +│ │ └── ui/ # Presentation layer +│ │ ├── home/ +│ │ │ ├── bloc/ +│ │ │ └── home_page.dart +│ │ └── appliance/ +│ │ ├── bloc/ +│ │ └── appliance_detail_page.dart +│ ├── test/ # Unit tests +│ └── pubspec.yaml +│ +├── .github/workflows/ +│ └── build-apk.yml # GitHub Actions CI +├── .circleci/ +│ └── config.yml # CircleCI configuration +├── HYBRID_INTEGRATION.md # Detailed integration docs +├── QUICK_REFERENCE.md # Quick reference guide +└── README.md # This file +``` + +## Getting Started + +### Prerequisites + +- **Android Studio**: Arctic Fox or later +- **Flutter SDK**: 3.36.5 or later +- **Dart SDK**: Included with Flutter +- **JDK**: 17 or later +- **Gradle**: 8.0+ + +### Installation + +1. **Clone the repository** + ```bash + git clone https://github.com/yourusername/sample_hydrid_android.git + cd sample_hydrid_android + ``` + +2. **Set up Flutter module** + ```bash + cd flutter_module + flutter pub get + cd .. + ``` + +3. **Generate Flutter code** (for Freezed, Mockito, etc.) + ```bash + cd flutter_module + dart run build_runner build --delete-conflicting-outputs + cd .. + ``` + +4. **Open in Android Studio** + - Open the root project in Android Studio + - Wait for Gradle sync to complete + +### Building + +#### Debug Build +```bash +./gradlew assembleDebug +``` + +#### Release Build +```bash +./gradlew assembleRelease +``` + +#### Flutter Module Build +```bash +cd flutter_module +flutter build aar +``` + +## Testing + +### Run Flutter Tests +```bash +cd flutter_module +flutter test +``` + +### Run Flutter Tests with Coverage +```bash +cd flutter_module +flutter test --coverage +``` + +### Generate Flutter Mocks +```bash +cd flutter_module +dart run build_runner build --delete-conflicting-outputs +``` + +### Run Android Unit Tests +```bash +./gradlew test +``` + +### Run Android Instrumented Tests +```bash +./gradlew connectedAndroidTest +``` + +## CI/CD + +This project includes two CI/CD configurations: + +### GitHub Actions +- **Workflow**: [.github/workflows/build-apk.yml](.github/workflows/build-apk.yml) +- **Triggers**: Push to `main`, `develop` branches +- **Steps**: + 1. Checkout code + 2. Set up Java 17 + 3. Set up Flutter + 4. Install Flutter dependencies + 5. Generate code (build_runner) + 6. Run Flutter tests + 7. Build Android APK + 8. Upload APK artifact + +### CircleCI +- **Config**: [.circleci/config.yml](.circleci/config.yml) +- **Triggers**: Push to any branch +- **Steps**: + 1. Checkout code + 2. Restore Flutter cache + 3. Install Flutter SDK + 4. Install dependencies + 5. Generate code + 6. Run tests with coverage + 7. Build APK + 8. Store artifacts + +## Documentation + +### Detailed Documentation +- **[HYBRID_INTEGRATION.md](HYBRID_INTEGRATION.md)** - Complete guide to the hybrid architecture + - Communication channels + - Android native implementation + - Flutter module implementation + - Navigation patterns + - Event handling + - Best practices + - Troubleshooting + +### Quick Reference +- **[QUICK_REFERENCE.md](QUICK_REFERENCE.md)** - Quick code snippets and patterns + - Event communication examples + - Navigation patterns + - Dependency injection + - Debugging tips + - Checklists + +## Key Concepts + +### FlutterEngine Caching +The app uses a cached FlutterEngine for better performance: +```kotlin +// Pre-warm at startup +val engine = FlutterEngine(context).apply { + dartExecutor.executeDartEntrypoint( + DartExecutor.DartEntrypoint.createDefault() + ) +} +FlutterEngineCache.getInstance().put(Constants.flutterEngineName, engine) + +// Reuse in activities +FlutterFragment.withCachedEngine(Constants.flutterEngineName).build() +``` + +### Event Communication +Events are sent via MethodChannel with JSON data: +```kotlin +// Android → Flutter +hybridEventBus.sendEventToHydrid("navigate", mapOf( + "routeName" to "/appliance/1", + "id" to "1", + "name" to "Refrigerator" +)) + +// Flutter → Android +await hybridBusService.sendEventToNative('navigateBack', {}); +``` + +### Navigation Pattern +1. Native screen starts `HybridFlutterActivity` +2. Activity sends navigation event with route and data +3. Flutter receives event and navigates to route +4. Flutter sends back event to close activity + +## Use Cases + +### Opening Appliance Details +1. User taps appliance card in native dashboard (Compose) +2. `DashBoardViewModel` starts `HybridFlutterActivity` +3. Sends "navigate" event with appliance data +4. Flutter `HybridBloc` receives event +5. Navigates to `ApplianceDetailPage` with data +6. User sees appliance details in Flutter UI + +### Returning to Native +1. User taps back button in Flutter screen +2. `ApplianceDetailBloc` sends "navigateBack" event +3. Android `HybridFlutterViewModel` receives event +4. Emits to `closeActivity` flow +5. `HybridFlutterActivity` finishes +6. User returns to native dashboard + +## Troubleshooting + +### Common Issues + +**Issue**: FlutterEngine not found +``` +Solution: Ensure FlutterEngineModule is providing the engine before +creating FlutterFragment +``` + +**Issue**: Events not received in Flutter +``` +Solution: +1. Verify channel name matches: "hybrid_channel" +2. Call hybridEventBus.register() in Activity +3. Check registerListener() is called in BLoC +``` + +**Issue**: Activity doesn't close on back +``` +Solution: Ensure closeActivity flow is collected in Activity: +lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + hydridViewModel.closeActivity.collect { finish() } + } +} +``` + +## Performance Considerations + +- **FlutterEngine caching**: Reduces cold start time from ~2s to ~200ms +- **Event queuing**: Prevents event loss during initialization +- **Lazy singletons**: Services are created only when needed +- **StateFlow**: Efficient state management with replay cache + +## Contributing + +Contributions are welcome! Please follow these steps: + +1. Fork the repository +2. Create a feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +### Code Style + +- **Android**: Follow [Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html) +- **Flutter**: Follow [Effective Dart](https://dart.dev/guides/language/effective-dart) +- Use meaningful variable names +- Add comments for complex logic +- Write unit tests for new features + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Acknowledgments + +- Flutter team for the excellent Flutter Module architecture +- Dagger Hilt for powerful dependency injection +- BLoC pattern for predictable state management +- Jetpack Compose for modern Android UI + +## Contact + +For questions or feedback, please open an issue on GitHub. + +--- + +**Built with ❤️ using Kotlin, Flutter, and modern Android development practices**