flutter_ads_kit 1.2.0
flutter_ads_kit: ^1.2.0 copied to clipboard
Production-ready Google AdMob for Flutter. Zero-config widgets for Banner, Native, Interstitial, Rewarded, Rewarded Interstitial, and App Open ads. Built-in iOS ATT and GDPR/UMP consent. Handles all e [...]
example/lib/main.dart
import 'package:flutter_ads_kit/flutter_ads_kit.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize the full ads stack:
// • iOS App Tracking Transparency prompt
// • GDPR/UMP consent form for EEA users
// • AdMob SDK
// • Preloads interstitial, rewarded, and rewarded-interstitial ads
await AdsManager.instance.initialize(
// adsEnabled: false // pass false after a "Remove Ads" IAP purchase
// Uncomment for children's apps (COPPA):
// tagForChildDirectedTreatment: true,
// tagForUnderAgeOfConsent: true,
//
// Add your physical-device hash (from Logcat / Xcode console) here:
// testDeviceIds: ['YOUR_DEVICE_HASH'],
);
// AppOpenAdManager is initialized separately to avoid a circular import.
if (AdsManager.instance.isAdsEnabled) {
AppOpenAdManager.instance.initialize();
}
runApp(const ApslAdsExampleApp());
}
class ApslAdsExampleApp extends StatelessWidget {
const ApslAdsExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'flutter_ads_kit Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _status = 'Ads initialised. Tap a button to test.';
void _setStatus(String msg) => setState(() => _status = msg);
// ── Interstitial ───────────────────────────────────────────────────────────
Future<void> _showInterstitial() async {
_setStatus('Showing interstitial…');
await InterstitialAdManager.instance.show(
onAdDismissed: () => _setStatus('Interstitial dismissed.'),
onNotAvailable: () => _setStatus('Interstitial not ready — try again.'),
);
}
// ── Rewarded ───────────────────────────────────────────────────────────────
Future<void> _showRewarded() async {
_setStatus('Showing rewarded ad…');
await RewardedAdManager.instance.show(
onUserEarnedReward: (RewardItem reward) =>
_setStatus('Earned ${reward.amount.toInt()} ${reward.type}!'),
onAdDismissed: () {
if (_status.startsWith('Showing')) {
_setStatus('Rewarded ad closed (no reward earned).');
}
},
onNotAvailable: () => _setStatus('Rewarded ad not ready — try again.'),
);
}
// ── Rewarded Interstitial ──────────────────────────────────────────────────
Future<void> _showRewardedInterstitial() async {
_setStatus('Showing rewarded interstitial…');
await RewardedInterstitialAdManager.instance.show(
onUserEarnedReward: (RewardItem reward) =>
_setStatus('Bonus: ${reward.amount.toInt()} ${reward.type}!'),
onAdDismissed: () {
if (_status.startsWith('Showing')) {
_setStatus('Rewarded interstitial closed.');
}
},
onNotAvailable: () => _setStatus('Not ready — try again.'),
);
}
// ── App Open ───────────────────────────────────────────────────────────────
void _showAppOpen() {
_setStatus('Showing app open ad…');
AppOpenAdManager.instance.showAdIfAvailable(
onAdDismissed: () => _setStatus('App open ad dismissed.'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutter_ads_kit Example'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Column(
children: [
// Status strip
ColoredBox(
color: Theme.of(context).colorScheme.secondaryContainer,
child: SizedBox(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(
_status,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [
// Adaptive banner
const _SectionHeader('Adaptive Banner'),
const Center(child: BannerAdWidget()),
const SizedBox(height: 16),
// Native — medium template (zero native setup needed)
const _SectionHeader('Native Ad — Medium Template'),
const NativeAdWidget(),
const SizedBox(height: 16),
// Native — small template
const _SectionHeader('Native Ad — Small Template'),
const NativeAdWidget(nativeAdSize: NativeAdSize.small),
const SizedBox(height: 16),
// Full-screen ad controls
const _SectionHeader('Full-Screen Ads'),
_AdButton(
label: 'Interstitial',
icon: Icons.open_in_full,
ready: InterstitialAdManager.instance.isReady,
onPressed: _showInterstitial,
),
const SizedBox(height: 8),
_AdButton(
label: 'Rewarded',
icon: Icons.stars_rounded,
ready: RewardedAdManager.instance.isReady,
onPressed: _showRewarded,
),
const SizedBox(height: 8),
_AdButton(
label: 'Rewarded Interstitial',
icon: Icons.card_giftcard,
ready: RewardedInterstitialAdManager.instance.isReady,
onPressed: _showRewardedInterstitial,
),
const SizedBox(height: 8),
_AdButton(
label: 'App Open',
icon: Icons.launch,
ready: true,
onPressed: _showAppOpen,
),
const SizedBox(height: 16),
// Fixed-size banner
const _SectionHeader('Banner — 300×250 (Medium Rectangle)'),
const Center(
child: BannerAdWidget(size: AdSize.mediumRectangle),
),
const SizedBox(height: 16),
// Simulated feed with native ads
const _SectionHeader('Native Ads in a Feed'),
..._feedItems(),
const SizedBox(height: 32),
],
),
),
// Sticky bottom banner
const BannerAdWidget(),
],
),
);
}
List<Widget> _feedItems() {
const total = 12;
final items = <Widget>[];
for (var i = 0; i < total; i++) {
items.add(
Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(child: Text('${i + 1}')),
title: Text('Article ${i + 1}'),
subtitle: const Text('Tap to read…'),
trailing: const Icon(Icons.chevron_right),
),
),
);
if ((i + 1) % 5 == 0 && i < total - 1) {
items.add(
const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: NativeAdWidget(nativeAdSize: NativeAdSize.small),
),
);
}
}
return items;
}
}
// ─────────────────────────────────────────────────────────────────────────────
class _SectionHeader extends StatelessWidget {
final String title;
const _SectionHeader(this.title);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
title,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
);
}
}
class _AdButton extends StatelessWidget {
final String label;
final IconData icon;
final bool ready;
final VoidCallback onPressed;
const _AdButton({
required this.label,
required this.icon,
required this.ready,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: FilledButton.icon(
onPressed: onPressed,
icon: Icon(icon),
label: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(label),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: ready ? Colors.green : Colors.orange,
borderRadius: BorderRadius.circular(4),
),
child: Text(
ready ? 'READY' : 'LOADING',
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
}
}