ann_flutter_flavor 0.2.4
ann_flutter_flavor: ^0.2.4 copied to clipboard
Multi-flavor Flutter toolkit. Reads annspec.yaml, generates typed flavor classes, and wires Android, iOS, Firebase, AdMob and RevenueCat.
ann_flutter_flavor #
A CLI tool and runtime API for ANN Flutter flavor management.
Reads a single annspec.yaml source-of-truth and:
- Generates typed Dart flavor code (
lib/generated/ann_flavor.g.dart) - Generates Firebase configuration scripts
- Wires the Gradle plugin into Android build files (
settings.gradle.kts,app/build.gradle.kts) - Generates per-flavor Android manifests with AdMob meta-data when configured
- Generates per-flavor iOS xcconfig files and patches
Info.plistwith variable references - Wires the CocoaPods plugin into the iOS
Podfile
Installation #
Add to your Flutter app's pubspec.yaml:
dependencies:
ann_flutter_flavor: ^0.2.2
IDE Plugin #
The ANN Flutter Flavor plugin for Android Studio and IntelliJ IDEA lets you author and validate annspec.yaml visually.
- Guided form UI for flavors, Firebase config, RevenueCat subscriptions, Google Sign-In keys, and AdMob IDs
- Spec validation highlights missing or invalid fields before you sync
- One-click sync via Tools → ANN Tools → Sync Spec
Install: Android Studio → Settings → Plugins → Marketplace → search "ANN Flutter Flavor"
Plugin ID:
dev.anntech.studio.flavorize
annspec.yaml format #
app:
android:
sdk:
minSdk: 23
compileSdk: 35
targetSdk: 35
default:
id: com.example.myapp
name: "My App"
version_name: 1.0.0
version_code: 10000
admob: # optional — enables AdMob for all flavors
gms_ads_id: "ca-app-pub-XXXX~XXXXXXXXXX"
build_types:
release:
firebase:
project_id: "my-firebase-prod"
path: "firebase/android/prod"
auth:
clientId: "000000000000-release.apps.googleusercontent.com"
reversedClientId: "com.googleusercontent.apps.000000000000-release"
debug:
firebase:
project_id: "my-firebase-dev"
path: "firebase/android/dev"
custom: # default-level custom attributes
revenuecat:
api_key: "rc_default_key"
entitlement_ids:
- standard
analytics:
enabled: true
flavor:
free:
id_suffix: .free
name: "My App Free"
main_file: "lib/flavors/main_free.dart"
admob: # flavor-level override
gms_ads_id: "ca-app-pub-YYYY~YYYYYYYYYY"
custom:
revenuecat:
api_key: "goog_XXXX"
entitlement_ids: ["standard"]
custom:
revenuecat:
api_key: "rc_free_key" # overrides default; entitlement_ids falls through
build_types:
debug:
custom:
revenuecat:
api_key: "rc_free_debug_key" # overrides free.release for debug builds
pro:
id_suffix: .pro
name: "My App Pro"
main_file: "lib/flavors/main_pro.dart"
custom:
revenuecat:
api_key: "rc_pro_key"
entitlement_ids:
- standard
- premium
ios:
default:
id: com.example.myapp
name: "My App"
version_name: 1.0.0
version_code: 10000
team_id: "YOURTEAMID"
admob: # optional — shared AdMob ID for iOS
gms_ads_id: "ca-app-pub-XXXX~XXXXXXXXXX"
flavor:
free:
id_suffix: .free
name: "My App Free"
main_file: "lib/flavors/main_free.dart"
pro:
id_suffix: .pro
name: "My App Pro"
main_file: "lib/flavors/main_pro.dart"
admob field cascade #
admob.gms_ads_id resolves in priority order: build_type → flavor → default.
- Set it once under
default:to share one AdMob App ID across all flavors - Override under a specific
flavor:to use a different ID for that flavor - Override under
flavor.build_types.<bt>:for build-type-level control - Presence of
admob:enables AdMob — no separateadmob_enabledflag needed
AdMob is only applicable to Android and iOS. Web and Windows have no AdMob support.
CLI Commands #
sync #
dart run ann_flutter_flavor sync
dart run ann_flutter_flavor sync -p ../my_flutter_app
What it generates / patches:
| File | Description |
|---|---|
lib/generated/ann_flavor.g.dart |
Typed AnnFlavorConfig subclass per flavor |
lib/generated/firebase_options_*.dart |
Generated by flutterfire configure for project_id build types |
fastlane/Fastfile + fastlane_*.rb |
CI/CD lanes per platform |
android/settings.gradle.kts |
Patches mavenCentral() + ANN plugin declaration |
android/app/build.gradle.kts |
Patches id("dev.anntech.flavorize") |
android/app/src/<flavor>/AndroidManifest.xml |
Per-flavor manifest; GMS Ads meta-data if admob: set |
ios/Flutter/<Flavor>Debug.xcconfig |
Per-flavor debug xcconfig |
ios/Flutter/<Flavor>Release.xcconfig |
Per-flavor release xcconfig |
ios/Runner/Info.plist |
Patches keys to use $(VARIABLE) references |
ios/Podfile |
Patches in CocoaPods plugin reference |
validate #
dart run ann_flutter_flavor validate
dart run ann_flutter_flavor validate -p ../my_flutter_app
Checks annspec.yaml for errors and warnings without writing any files. Useful in CI.
Runtime API #
Initialise in each flavor entry point #
// lib/flavors/main_free.dart
import 'package:ann_flutter_flavor/ann_flutter_flavor.dart';
import 'package:my_app/generated/ann_flavor.g.dart';
import 'dart:io';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
AnnFlavor.init(
config: FreeFlavor(),
platform: Platform.isAndroid ? AnnPlatform.android
: Platform.isIOS ? AnnPlatform.ios
: AnnPlatform.web,
);
runApp(const MyApp());
}
AnnFlavor.buildType is derived automatically from Flutter's kDebugMode / kReleaseMode —
no --dart-define needed.
Access flavor data anywhere #
AnnFlavor.key // "free"
AnnFlavor.current.name // "My App Free"
AnnFlavor.current.androidId // "com.example.myapp.free"
AnnFlavor.current.iosId // "com.example.myapp.free"
AnnFlavor.platform // AnnPlatform.android
AnnFlavor.buildType // "release" or "debug"
// RevenueCat subscriptions
final subs = AnnFlavor.current.subscriptions(AnnFlavor.platform);
subs?.first.apiKey // "goog_XXXX"
subs?.first.entitlementIds // ["standard"]
// Google Sign-In
final auth = AnnFlavor.current.auth(AnnFlavor.platform);
auth?.clientId // release client ID
final authDebug = AnnFlavor.current.authDebug(AnnFlavor.platform);
authDebug?.clientId // debug client ID
// Custom attributes — resolves cascade + build type automatically
AnnFlavor.current.custom('revenuecat')?.string('api_key')
AnnFlavor.current.custom('revenuecat')?.strings('entitlement_ids')
AnnFlavor.current.custom('analytics')?.boolean('enabled')
AdMob: The AdMob App ID is injected natively into
AndroidManifest.xmlandInfo.plistby thesynccommand. The AdMob SDK reads it automatically — just callMobileAds.instance.initialize(). No Dart API needed.
Custom attributes reference #
| Accessor | YAML type | Returns |
|---|---|---|
string(key) |
quoted string | String? |
boolean(key) |
true / false |
bool? |
integer(key) |
integer number | int? |
decimal(key) |
decimal number | double? |
strings(key) |
YAML list | List<String>? |
[key] |
any | dynamic |
All accessors return null if the group doesn't exist or the key is missing.
See docs/custom-attributes.md for the full cascade rules.
API reference #
| Symbol | Description |
|---|---|
AnnFlavor.init(config:, platform:) |
Initialise once at app startup |
AnnFlavor.current |
Active AnnFlavorConfig — throws if not initialised |
AnnFlavor.platform |
Active AnnPlatform — throws if not initialised |
AnnFlavor.key |
Shorthand for AnnFlavor.current.key |
AnnFlavorConfig.key |
Flavor key string (e.g. "free") |
AnnFlavorConfig.name |
Display name |
AnnFlavorConfig.androidId |
Full Android bundle ID |
AnnFlavorConfig.iosId |
Full iOS bundle ID |
AnnFlavorConfig.subscriptions(platform) |
List of AnnSubscription or null |
AnnFlavorConfig.auth(platform) |
Release AnnAuthConfig or null |
AnnFlavorConfig.authDebug(platform) |
Debug AnnAuthConfig or null |
AnnPlatform |
android, ios, web, windows |
AnnSubscription |
apiKey + entitlementIds |
AnnAuthConfig |
clientId + reversedClientId |
Build commands #
flutter run --flavor free -t lib/flavors/main_free.dart
flutter run --flavor pro -t lib/flavors/main_pro.dart
flutter build apk --flavor free -t lib/flavors/main_free.dart
flutter build appbundle --flavor pro -t lib/flavors/main_pro.dart
flutter build ipa --flavor free -t lib/flavors/main_free.dart
License #
MIT