11import 'package:flutter_news_app_mobile_client_full_source_code/app/config/app_environment.dart' ;
2+ import 'dart:io' show Platform;
23
34/// {@template app_config}
4- /// A centralized configuration class that provides all necessary environment-specific
5- /// variables for the application.
5+ /// A centralized configuration class that provides all necessary
6+ /// environment-specific variables for the application.
67///
7- /// This class uses factory constructors (`.production()` , `.development()` , `.demo()` )
8- /// to create an immutable configuration object based on the current build
9- /// environment, which is determined at compile time. All required values are
10- /// sourced from `--dart-define` variables, ensuring a clean separation of
11- /// configuration from code and preventing accidental use of development keys
12- /// in production builds.
8+ /// ## How It Works
9+ /// This class uses factory constructors (`.production()` , `.development()` ,
10+ /// `.demo()` ) to create an immutable configuration object based on the current
11+ /// build environment. All required values are sourced from `--dart-define`
12+ /// variables, ensuring a clean separation of configuration from code.
1313///
14- /// It includes robust validation to fail fast if required variables are missing,
15- /// providing clear error messages to the developer.
14+ /// ## Platform-Specific Keys
15+ /// Some services, like Firebase and OneSignal, require unique keys for Android
16+ /// and iOS. This class handles that complexity internally. It reads both
17+ /// platform-specific keys (e.g., `FIREBASE_ANDROID_APP_ID` and
18+ /// `FIREBASE_IOS_APP_ID` ) from the environment.
19+ ///
20+ /// It then exposes simple, platform-aware getters (e.g., `firebaseAppId` ).
21+ /// These getters automatically return the correct key based on the current
22+ /// operating system (`Platform.isAndroid` or `Platform.isIOS` ). This means the
23+ /// rest of the application can simply use `appConfig.firebaseAppId` without
24+ /// needing to know which platform it's running on.
25+ ///
26+ /// ## Validation
27+ /// The class includes a `_validateConfiguration` method that runs for
28+ /// `development` and `production` environments. It fails fast if:
29+ /// - A required key is missing.
30+ /// - A key still contains a placeholder value (e.g., 'YOUR_DEV_...').
31+ /// This prevents runtime errors and ensures a correctly configured build.
1632/// {@endtemplate}
1733class AppConfig {
1834 /// {@macro app_config}
1935 AppConfig ({
2036 required this .environment,
2137 required this .baseUrl,
22- required this .oneSignalAppId,
23- required this .firebaseApiKey,
24- required this .firebaseAppId,
38+ // Platform-specific keys
39+ required this .oneSignalAndroidAppId,
40+ required this .oneSignalIosAppId,
41+ required this .firebaseAndroidApiKey,
42+ required this .firebaseIosApiKey,
43+ required this .firebaseAndroidAppId,
44+ required this .firebaseIosAppId,
45+ // Shared keys
2546 required this .firebaseMessagingSenderId,
2647 required this .firebaseProjectId,
2748 required this .firebaseStorageBucket,
@@ -38,9 +59,20 @@ class AppConfig {
3859 final config = AppConfig (
3960 environment: AppEnvironment .production,
4061 baseUrl: const String .fromEnvironment ('BASE_URL' ),
41- oneSignalAppId: const String .fromEnvironment ('ONE_SIGNAL_APP_ID' ),
42- firebaseApiKey: const String .fromEnvironment ('FIREBASE_API_KEY' ),
43- firebaseAppId: const String .fromEnvironment ('FIREBASE_APP_ID' ),
62+ // Platform-specific
63+ oneSignalAndroidAppId: const String .fromEnvironment (
64+ 'ONE_SIGNAL_ANDROID_APP_ID' ,
65+ ),
66+ oneSignalIosAppId: const String .fromEnvironment ('ONE_SIGNAL_IOS_APP_ID' ),
67+ firebaseAndroidApiKey: const String .fromEnvironment (
68+ 'FIREBASE_ANDROID_API_KEY' ,
69+ ),
70+ firebaseIosApiKey: const String .fromEnvironment ('FIREBASE_IOS_API_KEY' ),
71+ firebaseAndroidAppId: const String .fromEnvironment (
72+ 'FIREBASE_ANDROID_APP_ID' ,
73+ ),
74+ firebaseIosAppId: const String .fromEnvironment ('FIREBASE_IOS_APP_ID' ),
75+ // Shared
4476 firebaseMessagingSenderId: const String .fromEnvironment (
4577 'FIREBASE_MESSAGING_SENDER_ID' ,
4678 ),
@@ -62,12 +94,17 @@ class AppConfig {
6294 factory AppConfig .demo () => AppConfig (
6395 environment: AppEnvironment .demo,
6496 baseUrl: '' , // No API access needed for in-memory demo
65- oneSignalAppId: 'YOUR_DEMO_ONESIGNAL_APP_ID' , // Placeholder for demo
97+ // Placeholders for demo
98+ oneSignalAndroidAppId: 'YOUR_DEMO_ONESIGNAL_ANDROID_APP_ID' ,
99+ oneSignalIosAppId: 'YOUR_DEMO_ONESIGNAL_IOS_APP_ID' ,
100+
66101 // Dummy Firebase values for demo mode.
67102 // These are required to initialize Firebase but won't be used for
68103 // actual backend communication in demo mode.
69- firebaseApiKey: 'demo-key' ,
70- firebaseAppId: '1:000000000000:android:0000000000000000000000' ,
104+ firebaseAndroidApiKey: 'demo-key-android' ,
105+ firebaseIosApiKey: 'demo-key-ios' ,
106+ firebaseAndroidAppId: '1:000000000000:android:0000000000000000000000' ,
107+ firebaseIosAppId: '1:000000000000:ios:0000000000000000000000' ,
71108 firebaseMessagingSenderId: '000000000000' ,
72109 firebaseProjectId: 'demo-project' ,
73110 firebaseStorageBucket: '' ,
@@ -87,18 +124,32 @@ class AppConfig {
87124 'BASE_URL' ,
88125 defaultValue: 'http://localhost:8080' ,
89126 ),
90- oneSignalAppId: const String .fromEnvironment (
91- 'ONE_SIGNAL_APP_ID' ,
92- defaultValue: 'YOUR_DEV_ONESIGNAL_APP_ID' ,
127+ // Platform-specific
128+ oneSignalAndroidAppId: const String .fromEnvironment (
129+ 'ONE_SIGNAL_ANDROID_APP_ID' ,
130+ defaultValue: 'YOUR_DEV_ONESIGNAL_ANDROID_APP_ID' ,
93131 ),
94- firebaseApiKey : const String .fromEnvironment (
95- 'FIREBASE_API_KEY ' ,
96- defaultValue: 'YOUR_DEV_FIREBASE_API_KEY ' ,
132+ oneSignalIosAppId : const String .fromEnvironment (
133+ 'ONE_SIGNAL_IOS_APP_ID ' ,
134+ defaultValue: 'YOUR_DEV_ONESIGNAL_IOS_APP_ID ' ,
97135 ),
98- firebaseAppId : const String .fromEnvironment (
99- 'FIREBASE_APP_ID ' ,
100- defaultValue: 'YOUR_DEV_FIREBASE_APP_ID ' ,
136+ firebaseAndroidApiKey : const String .fromEnvironment (
137+ 'FIREBASE_ANDROID_API_KEY ' ,
138+ defaultValue: 'YOUR_DEV_FIREBASE_ANDROID_API_KEY ' ,
101139 ),
140+ firebaseIosApiKey: const String .fromEnvironment (
141+ 'FIREBASE_IOS_API_KEY' ,
142+ defaultValue: 'YOUR_DEV_FIREBASE_IOS_API_KEY' ,
143+ ),
144+ firebaseAndroidAppId: const String .fromEnvironment (
145+ 'FIREBASE_ANDROID_APP_ID' ,
146+ defaultValue: 'YOUR_DEV_FIREBASE_ANDROID_APP_ID' ,
147+ ),
148+ firebaseIosAppId: const String .fromEnvironment (
149+ 'FIREBASE_IOS_APP_ID' ,
150+ defaultValue: 'YOUR_DEV_FIREBASE_IOS_APP_ID' ,
151+ ),
152+ // Shared
102153 firebaseMessagingSenderId: const String .fromEnvironment (
103154 'FIREBASE_MESSAGING_SENDER_ID' ,
104155 defaultValue: 'YOUR_DEV_FIREBASE_MESSAGING_SENDER_ID' ,
@@ -119,27 +170,54 @@ class AppConfig {
119170 /// The current build environment (e.g., production, development, demo).
120171 final AppEnvironment environment;
121172
122- /// The base URL for the backend API.
123- final String baseUrl;
124-
125- /// The OneSignal App ID for push notifications.
126- final String oneSignalAppId;
127-
128- /// The API key for the Firebase project.
129- final String firebaseApiKey;
173+ // --- Shared Configuration ---
130174
131- /// The App ID for the Firebase app .
132- final String firebaseAppId ;
175+ /// The base URL for the backend API (shared across platforms) .
176+ final String baseUrl ;
133177
134- /// The Sender ID for Firebase Cloud Messaging.
178+ /// The Sender ID for Firebase Cloud Messaging (shared across platforms) .
135179 final String firebaseMessagingSenderId;
136180
137- /// The Project ID for the Firebase project.
181+ /// The Project ID for the Firebase project (shared across platforms) .
138182 final String firebaseProjectId;
139183
140- /// The storage bucket for Firebase Storage.
184+ /// The storage bucket for Firebase Storage (shared across platforms) .
141185 final String firebaseStorageBucket;
142186
187+ // --- Platform-Specific Raw Values ---
188+
189+ /// The OneSignal App ID for the Android platform.
190+ final String oneSignalAndroidAppId;
191+
192+ /// The OneSignal App ID for the iOS platform.
193+ final String oneSignalIosAppId;
194+
195+ /// The API key for the Firebase Android app.
196+ final String firebaseAndroidApiKey;
197+
198+ /// The API key for the Firebase iOS app.
199+ final String firebaseIosApiKey;
200+
201+ /// The App ID for the Firebase Android app.
202+ final String firebaseAndroidAppId;
203+
204+ /// The App ID for the Firebase iOS app.
205+ final String firebaseIosAppId;
206+
207+ // --- Platform-Aware Getters ---
208+
209+ /// Returns the correct OneSignal App ID for the current platform.
210+ String get oneSignalAppId =>
211+ Platform .isAndroid ? oneSignalAndroidAppId : oneSignalIosAppId;
212+
213+ /// Returns the correct Firebase API Key for the current platform.
214+ String get firebaseApiKey =>
215+ Platform .isAndroid ? firebaseAndroidApiKey : firebaseIosApiKey;
216+
217+ /// Returns the correct Firebase App ID for the current platform.
218+ String get firebaseAppId =>
219+ Platform .isAndroid ? firebaseAndroidAppId : firebaseIosAppId;
220+
143221 /// A private static method to validate the loaded configuration.
144222 ///
145223 /// Throws a [FormatException] if any required environment variables are
@@ -161,9 +239,15 @@ class AppConfig {
161239 }
162240
163241 final placeholderKeys = [
164- if (config.oneSignalAppId.contains ('YOUR_' )) 'ONE_SIGNAL_APP_ID' ,
165- if (config.firebaseApiKey.contains ('YOUR_' )) 'FIREBASE_API_KEY' ,
166- if (config.firebaseAppId.contains ('YOUR_' )) 'FIREBASE_APP_ID' ,
242+ if (config.oneSignalAndroidAppId.contains ('YOUR_' ))
243+ 'ONE_SIGNAL_ANDROID_APP_ID' ,
244+ if (config.oneSignalIosAppId.contains ('YOUR_' )) 'ONE_SIGNAL_IOS_APP_ID' ,
245+ if (config.firebaseAndroidApiKey.contains ('YOUR_' ))
246+ 'FIREBASE_ANDROID_API_KEY' ,
247+ if (config.firebaseIosApiKey.contains ('YOUR_' )) 'FIREBASE_IOS_API_KEY' ,
248+ if (config.firebaseAndroidAppId.contains ('YOUR_' ))
249+ 'FIREBASE_ANDROID_APP_ID' ,
250+ if (config.firebaseIosAppId.contains ('YOUR_' )) 'FIREBASE_IOS_APP_ID' ,
167251 if (config.firebaseMessagingSenderId.contains ('YOUR_' ))
168252 'FIREBASE_MESSAGING_SENDER_ID' ,
169253 if (config.firebaseProjectId.contains ('YOUR_' )) 'FIREBASE_PROJECT_ID' ,
0 commit comments