flutter_ads_orchestrator 0.1.0 copy "flutter_ads_orchestrator: ^0.1.0" to clipboard
flutter_ads_orchestrator: ^0.1.0 copied to clipboard

Smart AdMob orchestration for Flutter apps: preload, throttle, caps, placement rules, UMP consent. Supports interstitial and rewarded ads.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_ads_orchestrator/flutter_ads_orchestrator.dart';

late final AdsOrchestrator orchestrator;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  orchestrator = AdsOrchestrator(
    config: const AdsConfig(
      // Always use test mode in this demo. **Never** ship release builds
      // with `testMode: true` — Google bans accounts that serve test ads
      // to real users.
      testMode: true,
      interstitial: InterstitialRules(
        // In test mode these are auto-overridden with Google's test IDs.
        adUnitIds: ['ca-app-pub-replace-with-yours/000000'],
        minInterval: Duration(seconds: 30),
        maxPerSession: 8,
        maxPerDay: 30,
        appOpenGuard: Duration(seconds: 5),
        placements: {
          'level_complete': PlacementRule.triggerEvery(3),
          'pause_menu': PlacementRule.disabled(),
          'game_over': PlacementRule.allowed(),
        },
      ),
      rewarded: RewardedRules(
        adUnitIds: ['ca-app-pub-replace-with-yours/000000'],
        minInterval: Duration(seconds: 15),
      ),
    ),
  );

  await orchestrator.initialize();
  runApp(const ExampleApp());
}

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flutter_ads_orchestrator demo',
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
      home: const MenuScreen(),
    );
  }
}

class MenuScreen extends StatelessWidget {
  const MenuScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Demo menu')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FilledButton(
              onPressed: () => Navigator.of(context).push(
                MaterialPageRoute<void>(builder: (_) => const GameScreen()),
              ),
              child: const Text('Play (interstitial demo)'),
            ),
            const SizedBox(height: 12),
            OutlinedButton(
              onPressed: () => Navigator.of(context).push(
                MaterialPageRoute<void>(builder: (_) => const SettingsScreen()),
              ),
              child: const Text('Settings (rewarded + privacy)'),
            ),
          ],
        ),
      ),
    );
  }
}

class GameScreen extends StatefulWidget {
  const GameScreen({super.key});
  @override
  State<GameScreen> createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> {
  int _level = 0;
  String _lastResult = '—';

  Future<void> _completeLevel() async {
    setState(() => _level++);
    final result = await orchestrator.showInterstitial(
      placement: 'level_complete',
    );
    if (!mounted) return;
    setState(() => _lastResult = _formatResult(result));
  }

  Future<void> _gameOver() async {
    final result = await orchestrator.showInterstitial(placement: 'game_over');
    if (!mounted) return;
    setState(() => _lastResult = _formatResult(result));
  }

  Future<void> _pauseMenu() async {
    // 'pause_menu' is configured as disabled — should always suppress.
    final result = await orchestrator.showInterstitial(placement: 'pause_menu');
    if (!mounted) return;
    setState(() => _lastResult = _formatResult(result));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Game')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text('Level $_level', style: const TextStyle(fontSize: 32)),
            const SizedBox(height: 24),
            FilledButton(
              onPressed: _completeLevel,
              child: const Text('Complete level (triggerEvery 3)'),
            ),
            const SizedBox(height: 8),
            OutlinedButton(
              onPressed: _gameOver,
              child: const Text('Game over (allowed)'),
            ),
            const SizedBox(height: 8),
            OutlinedButton(
              onPressed: _pauseMenu,
              child: const Text('Pause menu (disabled — always suppressed)'),
            ),
            const SizedBox(height: 24),
            Text('Last result: $_lastResult'),
          ],
        ),
      ),
    );
  }
}

class SettingsScreen extends StatefulWidget {
  const SettingsScreen({super.key});
  @override
  State<SettingsScreen> createState() => _SettingsScreenState();
}

class _SettingsScreenState extends State<SettingsScreen> {
  int _coins = 0;
  String _lastResult = '—';
  late final ValueNotifier<bool> _noAds;

  @override
  void initState() {
    super.initState();
    _noAds = ValueNotifier<bool>(orchestrator.noAdsFlag);
  }

  Future<void> _watchAdForCoins() async {
    final result = await orchestrator.showRewarded(
      placement: 'double_coins',
      onUserEarnedReward: (reward) {
        setState(() => _coins += reward.amount.toInt());
      },
    );
    if (!mounted) return;
    setState(() => _lastResult = _formatResult(result));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Settings')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text('Coins: $_coins', style: const TextStyle(fontSize: 24)),
            const SizedBox(height: 24),
            FilledButton(
              onPressed: _watchAdForCoins,
              child: const Text('Watch ad for coins (rewarded)'),
            ),
            const SizedBox(height: 24),
            ValueListenableBuilder<bool>(
              valueListenable: _noAds,
              builder: (context, value, _) => SwitchListTile(
                title: const Text('No-ads (premium toggle)'),
                value: value,
                onChanged: (v) async {
                  await orchestrator.setNoAdsFlag(v);
                  _noAds.value = v;
                },
              ),
            ),
            const SizedBox(height: 8),
            OutlinedButton(
              onPressed: () => orchestrator.showPrivacyOptions(),
              child: const Text('Show privacy options (UMP)'),
            ),
            const SizedBox(height: 24),
            Text('Last result: $_lastResult'),
          ],
        ),
      ),
    );
  }
}

String _formatResult(ShowResult result) {
  return result.when(
    shown: (id) => 'shown ($id)',
    suppressed: (reason) => 'suppressed (${reason.name})',
    failed: (err) => 'failed (${err.message})',
    notReady: () => 'not ready',
  );
}
1
likes
160
points
184
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Smart AdMob orchestration for Flutter apps: preload, throttle, caps, placement rules, UMP consent. Supports interstitial and rewarded ads.

Repository (GitHub)
View/report issues

Topics

#admob #ads #monetization #game-dev #consent

License

MIT (license)

Dependencies

flutter, google_mobile_ads, meta, shared_preferences

More

Packages that depend on flutter_ads_orchestrator