diff --git a/.gitignore b/.gitignore index de77d82..e79b2ff 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ app.*.symbols # Obfuscation related app.*.map.json +# Google Services +google-services.json + # Android Studio will place build artifacts here /android/app/debug /android/app/profile diff --git a/README.md b/README.md index 6b420e1..0a15f49 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ lib/ ### Prerequisites -- Flutter SDK (>=3.0.0) -- Dart SDK (>=3.0.0) +- Flutter SDK (>=3.27.0) +- Dart SDK (>=3.8.0) - Android Studio / VS Code with Flutter extensions - Xcode (for iOS development on macOS) @@ -219,7 +219,8 @@ lib/ 1. **Rename the project** (if needed) - Update package name from `flutter_starter` to your project name 2. **Configure your environment** - See [Configuration System](#-configuration-system) below 3. **Set up Firebase** (optional) - For remote feature flags and performance monitoring - - Add `google-services.json` (Android) and `GoogleService-Info.plist` (iOS) + - **Setup Firebase Config**: Add `google-services.json` (Android) and `GoogleService-Info.plist` (iOS). + > **Note**: These files are gitignored for security. You must add them manually for local development. For CI/CD, use environment variables to generate them. - Initialize Firebase in your app 4. **Customize the theme** - Edit `lib/shared/theme/app_theme.dart` 5. **Explore example features** - Check out `lib/features/` for examples: diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 5d0276d..efe974a 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -42,3 +42,5 @@ android { flutter { source = "../.." } + +apply(plugin = "com.google.gms.google-services") diff --git a/android/build.gradle.kts b/android/build.gradle.kts index dbee657..edb19ba 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,3 +1,9 @@ +plugins { + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false + id("com.google.gms.google-services") version "4.3.15" apply false +} + allprojects { repositories { google() @@ -5,18 +11,26 @@ allprojects { } } -val newBuildDir: Directory = - rootProject.layout.buildDirectory - .dir("../../build") - .get() +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) project.layout.buildDirectory.value(newSubprojectBuildDir) + + afterEvaluate { + if (project.plugins.hasPlugin("java") || project.plugins.hasPlugin("com.android.library")) { + project.extensions.findByType()?.apply { + toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } + } + } + } } + subprojects { - project.evaluationDependsOn(":app") + if (project.name != "app") { + project.evaluationDependsOn(":app") + } } tasks.register("clean") { diff --git a/android/gradle.properties b/android/gradle.properties index fbee1d8..fad9e3e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,2 +1,6 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true +# Enable toolchain auto-provisioning +org.gradle.java.installations.auto-download=true +# Use Java 21 from Android Studio for Gradle daemon (to compile build scripts) +org.gradle.java.home=C:\\Program Files\\Android\\Android Studio\\jbr diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index e4ef43f..ca025c8 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index ca7fe06..8337b61 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -21,6 +21,8 @@ plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.11.1" apply false id("org.jetbrains.kotlin.android") version "2.2.20" apply false + id("com.google.gms.google-services") version "4.3.15" apply false + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } include(":app") diff --git a/docs/deployment/deployment.md b/docs/deployment/deployment.md index 0a91219..c99f0dd 100644 --- a/docs/deployment/deployment.md +++ b/docs/deployment/deployment.md @@ -448,7 +448,7 @@ firebase deploy --only hosting 1. **Add Dependencies** to `pubspec.yaml`: ```yaml dependencies: - firebase_core: ^3.0.0 + firebase_core: ^2.24.2 firebase_crashlytics: ^4.0.0 ``` @@ -477,6 +477,7 @@ void main() async { 3. **Configure Firebase Projects**: - Create Firebase projects for each environment - Add `google-services.json` (Android) and `GoogleService-Info.plist` (iOS) + - **Note:** These files are gitignored. For CI/CD (e.g., GitHub Actions), store them as Base64 secrets (`ANDROID_GOOGLE_SERVICES_JSON`, `IOS_GOOGLE_SERVICE_INFO`) and decode them during the build process. - Place in appropriate flavor directories ### Analytics Integration diff --git a/docs/deployment/monitoring-analytics.md b/docs/deployment/monitoring-analytics.md index 55d9e70..a2d6c0f 100644 --- a/docs/deployment/monitoring-analytics.md +++ b/docs/deployment/monitoring-analytics.md @@ -23,7 +23,7 @@ Update `pubspec.yaml`: ```yaml dependencies: - firebase_core: ^3.0.0 + firebase_core: ^2.24.2 firebase_crashlytics: ^4.0.0 ``` diff --git a/docs/guides/onboarding/getting-started.md b/docs/guides/onboarding/getting-started.md index 6b5c80b..4280a22 100644 --- a/docs/guides/onboarding/getting-started.md +++ b/docs/guides/onboarding/getting-started.md @@ -2,21 +2,6 @@ This guide will help you set up your development environment and get the Flutter Starter project running. -## Prerequisites - -Before you begin, ensure you have the following installed: - -- **Flutter SDK**: Version 3.0.0 or higher - - Check your version: `flutter --version` - - Install/update: [Flutter Installation Guide](https://docs.flutter.dev/get-started/install) - -- **Dart SDK**: Version 3.0.0 or higher (included with Flutter) - -- **IDE**: Choose one of the following: - - **VS Code** (recommended): Install Flutter and Dart extensions - - **Android Studio**: Install Flutter and Dart plugins - - **IntelliJ IDEA**: Install Flutter and Dart plugins - - **Platform-specific tools** (for your target platforms): - **Android**: Android Studio with Android SDK - **iOS**: Xcode (macOS only) diff --git a/lib/core/config/env_config.dart b/lib/core/config/env_config.dart index 4d3f436..79c110a 100644 --- a/lib/core/config/env_config.dart +++ b/lib/core/config/env_config.dart @@ -2,8 +2,11 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; /// Environment configuration loader with fallback chain: /// 1. .env file (for local development) -/// 2. --dart-define flags (for CI/CD) -/// 3. Default values +/// 2. Default values +/// +/// Note: --dart-define flags are compile-time only and cannot be accessed +/// dynamically at runtime. They must be accessed via const +/// String.fromEnvironment() for specific known keys if needed. /// /// Usage: /// ```dart @@ -20,7 +23,7 @@ class EnvConfig { /// This should be called before runApp() in main.dart /// /// The .env file is optional. If it doesn't exist, the system will fall back - /// to --dart-define flags or default values. + /// to default values. /// /// Note: For .env to be loaded, it must be added to pubspec.yaml assets /// after creating it from .env.example @@ -50,13 +53,11 @@ class EnvConfig { /// Get environment variable with fallback chain: /// 1. .env file value (if loaded) - /// 2. --dart-define flag value - /// 3. Default value (if provided) + /// 2. Default value (if provided) /// /// Parameters: /// - [key]: The environment variable key - /// - [defaultValue]: Optional default value if not found in .env or - /// --dart-define + /// - [defaultValue]: Optional default value if not found in .env /// /// Returns: /// The environment variable value, or [defaultValue] if not found @@ -78,17 +79,14 @@ class EnvConfig { return value; } } on Exception { - // Variable not found in .env, continue to next priority + // Variable not found in .env, continue to default } } - // Priority 2: Check --dart-define flags - final dartDefineValue = String.fromEnvironment(key); - if (dartDefineValue.isNotEmpty) { - return dartDefineValue; - } - - // Priority 3: Return default value + // Return default value + // Note: --dart-define flags are compile-time only and cannot be + // accessed dynamically at runtime. They must be accessed via + // const String.fromEnvironment() for specific known keys. return defaultValue; } @@ -102,21 +100,11 @@ class EnvConfig { try { return dotenv.getBool(key, fallback: defaultValue); } on Exception { - // Variable not found in .env, continue to next priority + // Variable not found in .env, continue to default } } - // Priority 2: Check --dart-define flags - final dartDefineValue = String.fromEnvironment(key); - if (dartDefineValue.isNotEmpty) { - final lowerValue = dartDefineValue.toLowerCase().trim(); - return lowerValue == 'true' || - lowerValue == '1' || - lowerValue == 'yes' || - lowerValue == 'on'; - } - - // Priority 3: Return default value + // Return default value return defaultValue; } @@ -129,17 +117,11 @@ class EnvConfig { try { return dotenv.getInt(key, fallback: defaultValue); } on Exception { - // Variable not found in .env, continue to next priority + // Variable not found in .env, continue to default } } - // Priority 2: Check --dart-define flags - final dartDefineValue = String.fromEnvironment(key); - if (dartDefineValue.isNotEmpty) { - return int.tryParse(dartDefineValue) ?? defaultValue; - } - - // Priority 3: Return default value + // Return default value return defaultValue; } @@ -152,23 +134,17 @@ class EnvConfig { try { return dotenv.getDouble(key, fallback: defaultValue); } on Exception { - // Variable not found in .env, continue to next priority + // Variable not found in .env, continue to default } } - // Priority 2: Check --dart-define flags - final dartDefineValue = String.fromEnvironment(key); - if (dartDefineValue.isNotEmpty) { - return double.tryParse(dartDefineValue) ?? defaultValue; - } - - // Priority 3: Return default value + // Return default value return defaultValue; } /// Check if an environment variable exists /// - /// Returns true if the variable exists in .env file or --dart-define + /// Returns true if the variable exists in .env file static bool has(String key) { // Check .env file (if loaded) if (_isInitialized) { @@ -181,8 +157,8 @@ class EnvConfig { // Variable not found in .env } } - // Check --dart-define flags - return String.fromEnvironment(key).isNotEmpty; + // Note: --dart-define values cannot be checked dynamically at runtime + return false; } /// Get all environment variables as a map diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index e6a15b0..4dbb4ea 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -13,7 +13,7 @@ import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) - FirebaseRemoteConfigPlugin.register(with: registry.registrar(forPlugin: "FirebaseRemoteConfigPlugin")) + FLTFirebaseRemoteConfigPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseRemoteConfigPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 010df98..a92e4df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "8a1f5f3020ef2a74fb93f7ab3ef127a8feea33a7a2276279113660784ee7516a" + sha256: "37a42d06068e2fe3deddb2da079a8c4d105f241225ba27b7122b37e9865fd8f7" url: "https://pub.dev" source: hosted - version: "1.3.64" + version: "1.3.35" analyzer: dependency: transitive description: @@ -237,74 +237,74 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "1f2dfd9f535d81f8b06d7a50ecda6eac1e6922191ed42e09ca2c84bd2288927c" + sha256: "26de145bb9688a90962faec6f838247377b0b0d32cc0abecd9a4e43525fc856c" url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "2.32.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 + sha256: "8bcfad6d7033f5ea951d15b867622a824b13812178bfec0c779b9d81de011bbb" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "5.4.2" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: ff18fabb0ad0ed3595d2f2c85007ecc794aadecdff5b3bb1460b7ee47cded398 + sha256: eb3afccfc452b2b2075acbe0c4b27de62dd596802b4e5e19869c1e926cbb20b3 url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "2.24.0" firebase_performance: dependency: "direct main" description: name: firebase_performance - sha256: "437ab1b317db59ac220553345f60042d6585b561e1a4ea75f2f59f7573ca9bcd" + sha256: dbcfc300755c4bb866988de20a491f0b53e1a0d14c375a2c31aa53ca82174c5b url: "https://pub.dev" source: hosted - version: "0.11.1+2" + version: "0.9.4+7" firebase_performance_platform_interface: dependency: transitive description: name: firebase_performance_platform_interface - sha256: "0e84f5a885f0c9ac8e6796ce2ff61488632beb99645b9429560e694bde2a4352" + sha256: "191c9945c2ea4359cb57dc086463b2a25b0f9d8d42f66a0be4c1a7133e26ebc8" url: "https://pub.dev" source: hosted - version: "0.1.6+2" + version: "0.1.4+35" firebase_performance_web: dependency: transitive description: name: firebase_performance_web - sha256: d13aa3546858107dec8b92b2eb2de56e53c940a1a5a0bb2451a6eadb65486450 + sha256: "9f03a53f55697b206393366bf138e382cbd845d5021b5be6f7fc97b338da2cb5" url: "https://pub.dev" source: hosted - version: "0.1.8" + version: "0.1.6+7" firebase_remote_config: dependency: "direct main" description: name: firebase_remote_config - sha256: "5d23c7021e69fbc9ef489ebcf4b1b941575e34ebacc7f20173c2a97f37f45b74" + sha256: "653bd94b68e2c4e89eca10db90576101f1024151f39f2d4e7c64ae6a90a5f9c5" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "4.4.7" firebase_remote_config_platform_interface: dependency: transitive description: name: firebase_remote_config_platform_interface - sha256: b9c80a6cbc43367fdb2d4f441546e7c5330e5dc256659b58f5c0ab67cd332f43 + sha256: "24a2c445b15de3af7e4582ebceb2aa9a1e3731d0202cb3e7a1e03012440fa07d" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "1.4.35" firebase_remote_config_web: dependency: transitive description: name: firebase_remote_config_web - sha256: "2a465562d7d35c3a7f4956d440d5ac171e6ce65974b2225fd17b45303f88aa94" + sha256: "525aa3000fd27cd023841c802010a06515e564aab2f147aa964b35f54abbf449" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.6.7" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index af9ed03..9e010dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,9 +18,9 @@ dependencies: equatable: ^2.0.7 # Firebase - Remote Config for feature flags - firebase_core: ^4.2.1 - firebase_performance: ^0.11.1+2 - firebase_remote_config: ^6.1.1 + firebase_core: ^2.24.2 + firebase_performance: ^0.9.3+8 + firebase_remote_config: ^4.3.6 # Flutter SDK - Core Flutter framework flutter: @@ -50,7 +50,7 @@ dependencies: intl: ^0.20.2 # Code Generation - Runtime annotations for JSON serialization - # Used for @JsonSerializable annotations (Group 7 implementation) + # Used for @JsonSerializable annotations json_annotation: ^4.9.0 # Logging - Comprehensive logging solution with multiple outputs @@ -81,11 +81,11 @@ dev_dependencies: sdk: flutter # Code Generation - Generates immutable classes, unions, and more - # Used for @freezed code generation (Group 7 implementation) + # Used for @freezed code generation freezed: ^3.2.3 # Code Generation - Generates JSON serialization/deserialization code - # Used for @JsonSerializable code generation (Group 7 implementation) + # Used for @JsonSerializable code generation json_serializable: ^6.11.1 # Testing - Mocking library for unit tests (no code generation required) @@ -95,8 +95,7 @@ dev_dependencies: very_good_analysis: ^10.0.0 # REMOVED UNUSED DEV DEPENDENCIES: - # go_router_builder: ^4.1.1 - Not used (go_router removed), can add back when implementing routing - # retrofit_generator: ^10.1.4 - Not used (retrofit removed), can add back when implementing type-safe HTTP client + # retrofit_generator: ^10.1.4 - Not used, can add back when implementing type-safe HTTP client # riverpod_generator: ^3.0.3 - Not used (using manual providers), can add back when using code generation # For information on the generic Dart part of this file, see the