vie_app_ads_manager 1.0.6
vie_app_ads_manager: ^1.0.6 copied to clipboard
Simple ads manager for admob and applovin ads
vie_app_ads_manager #
A lightweight, opinionated ads manager for Flutter that unifies AdMob (Google Mobile Ads) and AppLovin MAX into a single, simple API.
Features #
- Full Ad Format Support: Interstitial, Rewarded, Rewarded-Interstitial (AdMob), App Open, Banner, Native
- Smart Fallback System: Automatic fallback from AdMob to AppLovin MAX when configured
- Remote Config Driven Providers: Select AdMob/MAX and enable flags via Firebase Remote Config
- Widget-Based Ads: Banner and Native ad widgets that auto-select provider via RC
- Event Streaming: Real-time ad lifecycle events for UI state management
- Test Mode Support: Built-in AppLovin MAX mediation debugger and AdMob test ads
- Robust Error Handling: Comprehensive logging and state management
Works with: google_mobile_ads, applovin_max.
Installation #
Add to your pubspec.yaml:
dependencies:
vie_app_ads_manager: ^1.0.6
Then run:
flutter pub get
Platform setup #
Follow the official setup for each SDK your app will use and apply the additional configuration below.
Android configuration #
-
Project-level Gradle (
android/build.gradle)Add the AppLovin repository and configure dependencies with version alignment:
buildscript { repositories { google() mavenCentral() maven { url = uri("https://artifacts.applovin.com/android") } } dependencies { classpath 'com.android.tools.build:gradle:8.1.2' // Use your current version classpath 'com.google.gms:google-services:4.3.15' // Add this line for Google Services } } allprojects { repositories { google() mavenCentral() maven { url = uri("https://artifacts.applovin.com/android") } } configurations.all { resolutionStrategy { force( "com.google.android.gms:play-services-ads:24.7.0", "com.applovin.mediation:google-adapter:24.7.0.0" ) } } }Note: Adapt versions to the latest recommended by google_mobile_ads and applovin_max packages.
-
App-level Gradle (
android/app/build.gradle)Add the mediation adapter dependencies to the
dependenciesblock:dependencies { // Align Google Mobile Ads SDK with AppLovin Google adapter implementation("com.google.android.gms:play-services-ads:24.7.0") implementation("com.applovin.mediation:google-adapter:24.7.0.0") } -
AndroidManifest (
android/app/src/main/AndroidManifest.xml)Add required permissions, AdMob application ID, and AppLovin MAX activities:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:name="${applicationName}" android:icon="@mipmap/launcher_icon" android:label="YOUR_APP_NAME"> <!-- Your main activity configuration --> <activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:exported="true" android:hardwareAccelerated="true" android:launchMode="singleTask" android:taskAffinity="${applicationId}" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- AdMob App ID required for Google Mobile Ads SDK initialization --> <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="YOUR_ADMOB_APP_ID_ANDROID" /> <!-- AppLovin MAX Ad Activities - Force them to use our task --> <activity android:name="com.applovin.adview.AppLovinInterstitialActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:excludeFromRecents="true" android:taskAffinity="${applicationId}" tools:replace="android:configChanges,android:taskAffinity" /> <activity android:name="com.applovin.adview.AppLovinFullscreenActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:excludeFromRecents="true" android:taskAffinity="${applicationId}" tools:replace="android:configChanges,android:taskAffinity" /> <!-- Optional: For webview-based ads or browsers --> <activity android:name="com.applovin.sdk.AppLovinWebViewActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:excludeFromRecents="true" android:taskAffinity="${applicationId}" tools:replace="android:configChanges,android:taskAffinity" /> <!-- Optional: If using the mediation debugger --> <!-- REMOVE THIS IN PRODUCTION --> <!-- <activity--> <!-- android:name="com.applovin.mediation.MaxDebuggerActivity"--> <!-- android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"--> <!-- android:excludeFromRecents="true"--> <!-- android:taskAffinity="${applicationId}"--> <!-- tools:replace="android:configChanges,android:taskAffinity" />--> <meta-data android:name="flutterEmbedding" android:value="2" /> </application> <queries> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent> </queries> </manifest>Important:
- Replace
YOUR_ADMOB_APP_ID_ANDROIDwith your real AdMob app ID - Replace
YOUR_APP_NAMEwith your app name - The AppLovin MAX activities ensure ads stay within your app's task
- Uncomment the debugger activity only during development
- The
<queries>tag is required for some ad networks to work properly
- Replace
iOS configuration #
-
Google Mobile Ads (AdMob)
- Add
GADApplicationIdentifierto your iOSInfo.plistwith your AdMob app ID. - See: https://pub.flutter-io.cn/packages/google_mobile_ads
- Add
-
AppLovin MAX
- Initialize the SDK with your
sdkKeyat runtime (no extra Info.plist keys are required for basic setup). - See: https://pub.flutter-io.cn/packages/applovin_max
- Initialize the SDK with your
Make sure you use your own ad unit IDs in production. Use test IDs during development.
Getting started #
Import the package:
import 'package:vie_app_ads_manager/ads_manager.dart';
Initialize as early as possible (e.g., in main or first page load). You must initialize Firebase and the provided AnalyticsManager to fetch Remote Config before initializing AdsManager:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: const Home());
}
}
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool _initializing = true;
@override
void initState() {
super.initState();
_initAds();
}
Future<void> _initAds() async {
// 1) Initialize Analytics + Remote Config
await AnalyticsManager.instance.init(
options: /* Your DefaultFirebaseOptions.currentPlatform */,
minimumFetchInterval: Duration.zero,
);
// 2) Provide your AdMob and (optionally) AppLovin MAX IDs
final admobIds = AdmobIds(
appIdAndroid: 'YOUR_ADMOB_APP_ID_ANDROID',
appIdIos: 'YOUR_ADMOB_APP_ID_IOS',
bannerId: 'YOUR_ADMOB_BANNER_ID',
interstitialId: 'YOUR_ADMOB_INTERSTITIAL_ID',
rewardedId: 'YOUR_ADMOB_REWARDED_ID',
rewardedInterstitialId: 'YOUR_ADMOB_REWARDED_INTERSTITIAL_ID',
nativeId: 'YOUR_ADMOB_NATIVE_ID',
appOpenId: 'YOUR_ADMOB_APPOPEN_ID',
);
// Optional: provide AppLovin MAX IDs to enable fallback or to force MAX
final maxIds = MaxIds(
sdkKey: 'YOUR_MAX_SDK_KEY',
bannerId: 'YOUR_MAX_BANNER_ID',
interstitialId: 'YOUR_MAX_INTERSTITIAL_ID',
rewardedId: 'YOUR_MAX_REWARDED_ID',
nativeId: 'YOUR_MAX_NATIVE_ID',
appOpenId: 'YOUR_MAX_APPOPEN_ID',
);
// 3) Initialize AdsManager (it will read provider flags from Remote Config)
await AdsManager.instance.initialize(
admobIds: admobIds,
maxIds: maxIds,
adjustAppToken: 'YOUR_ADJUST_APP_TOKEN',
);
if (!mounted) return;
setState(() => _initializing = false);
}
}
## Remote Config Provider Control
Provider selection and feature flags are controlled via Firebase Remote Config (RC). Configure these keys in RC:
- `show_banner` (bool): enable/disable banner widget
- `native_ad_enabled` (bool): enable/disable native widget
- `show_app_open` (bool): enable/disable app open button/flow
- `banner_provider` (int): 0=off, 1=AdMob only, 2=MAX only
- `interstitial_provider` (int): 0=off, 1=AdMob only, 2=MAX only
- `reward_provider` (int): 0=off, 1=AdMob only, 2=MAX only
- `app_open_provider` (int): 0=off, 1=AdMob only, 2=MAX only
- `native_ad_provider` (int): 0=off, 1=AdMob only, 2=MAX only
AdsManager reads these values during `initialize()` via `AnalyticsManager`.
### How selection works
- `0` → No-Op: show methods return false; widgets render nothing
- `1` → AdMob only (no MAX fallback)
- `2` → MAX only
- Otherwise: default logic attempts AdMob first, with MAX as fallback when available
### Interstitial
```dart
// Provider is selected via RC
final shown = await AdsManager.instance.showInterstitial();
Rewarded #
final shown = await AdsManager.instance.showRewarded(
onEarnedReward: (amount) {
// grant reward
},
);
App Open #
final shown = await AdsManager.instance.showAppOpen();
Widgets #
Banner #
A banner widget that auto-selects provider via Remote Config, with automatic fallback when allowed.
// Default behavior (provider sourced from RC)
const BannerAdManager()
// Custom size
const BannerAdManager(adSize: AdSize.largeBanner)
Note: AdSize is re-exported by this package. You only need:
import 'package:ads_manager/ads_manager.dart';
No direct import from google_mobile_ads is required just to use AdSize.
Native #
A native ad widget that auto-selects provider via Remote Config, with automatic fallback when allowed.
// Default behavior (provider sourced from RC)
const NativeAdManager(height: 300)
// Custom styling
NativeAdManager(
height: 300,
style: NativeTemplateStyle(templateType: TemplateType.medium),
)
Events #
Listen to the stream for ad lifecycle events to drive UI state (e.g., loading spinners):
final sub = AdsManager.instance.onEvent.listen((event) {
final type = event.keys.first; // AdUnitType
final ev = event.values.first; // AdEventType
// handle
});
AdUnitType: banner, interstitial, rewarded, rewardedInterstitial, native, appOpen
AdEventType: loading, loaded, failedToLoad, showed, dismissed, failedToShow, earnedReward
Testing & Debugging #
AppLovin MAX Test Mode #
The ads manager automatically enables AppLovin MAX mediation debugger during initialization for testing purposes. This provides:
- Real-time mediation waterfall information
- Network adapter status
- Test ad controls
- Revenue and performance metrics
AdMob Test Ads Helper #
You can switch to AdMob test IDs at runtime and preload again:
await AdsManager.instance.showTestAds();
This is handy to validate your integration without touching your production IDs.
Provider-Based Testing #
Use the helper to switch to AdMob test IDs. To simulate networks, change RC provider keys at runtime and call AnalyticsManager().refreshRemoteConfig() before showing again.
// Switch to AdMob test IDs and preload test ads
await AdsManager.instance.showTestAds();
// Change RC: banner_provider / interstitial_provider / reward_provider / app_open_provider
await AnalyticsManager().refreshRemoteConfig();
Example #
See the example/ app for a full usage demo with buttons for interstitial, rewarded, app open, banner, and native ads plus event-handling.
Notes & Tips #
General #
- Always use Google's test IDs or your own test placements during development to avoid policy violations.
- AppLovin MAX requires your real SDK key and ad unit IDs. Ensure network permissions and platform setup are complete.
- If you prefer not to use MAX, initialize without
max:and the manager will work with AdMob only.
Provider Behavior #
- Provider 0 (no ads): All show methods return
false. Banner/Native widgets render nothing and do not load. - Provider 1 (AdMob only): No fallback to MAX, even if MAX is configured. Use this for pure AdMob testing.
- Provider 2 (MAX only): Direct MAX ad loading, bypasses AdMob entirely.
- Default (null provider): Smart fallback system - tries AdMob first, falls back to MAX on failure.
- Widgets: Banner and Native widgets respect provider settings and handle fallbacks accordingly.
Performance #
- MAX mediation debugger adds overhead - disable in production builds if needed.
- Provider selection allows you to test individual networks without interference.
- Event streaming helps optimize UI responsiveness during ad loading.
License #
MIT