admanagekit-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/README.md +851 -0
- package/content/docs/AD_FREQUENCY_CONTROL.md +450 -0
- package/content/docs/AD_LOADING_STRATEGIES.md +369 -0
- package/content/docs/API_REFERENCE.md +734 -0
- package/content/docs/APP_PURCHASE_GUIDE.md +704 -0
- package/content/docs/BANNER_AD_IMPROVEMENTS.md +325 -0
- package/content/docs/COMPOSE_INTEGRATION.md +477 -0
- package/content/docs/CONFIGURATION_USAGE.md +168 -0
- package/content/docs/INTERSTITIAL_BUILDER_GUIDE.md +518 -0
- package/content/docs/JAVA_USAGE_GUIDE.md +785 -0
- package/content/docs/LOADING_STRATEGY_EXAMPLES.md +463 -0
- package/content/docs/NATIVE_AD_MANAGER_ENHANCEMENTS.md +347 -0
- package/content/docs/NATIVE_AD_PRELOADING.md +467 -0
- package/content/docs/NATIVE_TEMPLATE_VIEW.md +413 -0
- package/content/docs/app-open-ads.md +412 -0
- package/content/docs/interstitial-ads.md +269 -0
- package/content/docs/native-ads-caching.md +182 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.1.0.md +156 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.2.0.md +248 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.3.0.md +280 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.5.0.md +73 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.6.0.md +265 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.7.0.md +168 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.8.0.md +153 -0
- package/content/docs/release-notes/RELEASE_NOTES_v2.9.0.md +479 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.0.0.md +343 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.1.0.md +131 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.3.0.md +252 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.3.2.md +215 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.3.3.md +116 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.3.4.md +142 -0
- package/content/docs/release-notes/RELEASE_NOTES_v3.3.5.md +94 -0
- package/content/docs/rewarded-ads.md +623 -0
- package/content/wiki/Ad-Loading-Strategies.md +209 -0
- package/content/wiki/App-Open-Ads.md +189 -0
- package/content/wiki/Banner-Ads.md +133 -0
- package/content/wiki/Billing-Integration.md +69 -0
- package/content/wiki/Configuration.md +252 -0
- package/content/wiki/Consumable-Products.md +166 -0
- package/content/wiki/Home.md +144 -0
- package/content/wiki/Interstitial-Ads.md +313 -0
- package/content/wiki/Jetpack-Compose.md +270 -0
- package/content/wiki/NativeAdManager.md +220 -0
- package/content/wiki/Purchase-Categories.md +94 -0
- package/content/wiki/Rewarded-Ads.md +420 -0
- package/content/wiki/Subscription-Upgrades.md +278 -0
- package/content/wiki/Subscriptions.md +368 -0
- package/content/wiki/_Footer.md +3 -0
- package/content/wiki/_Sidebar.md +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +18 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/code-generation.d.ts +2 -0
- package/dist/tools/code-generation.js +264 -0
- package/dist/tools/code-generation.js.map +1 -0
- package/dist/tools/documentation.d.ts +2 -0
- package/dist/tools/documentation.js +202 -0
- package/dist/tools/documentation.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +83 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/doc-loader.d.ts +17 -0
- package/dist/utils/doc-loader.js +245 -0
- package/dist/utils/doc-loader.js.map +1 -0
- package/dist/utils/search.d.ts +2 -0
- package/dist/utils/search.js +62 -0
- package/dist/utils/search.js.map +1 -0
- package/dist/utils/templates.d.ts +60 -0
- package/dist/utils/templates.js +793 -0
- package/dist/utils/templates.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# App Open Ads - AdManageKit v3.3.5
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
AdManageKit provides lifecycle-aware app open ad management through the `AppOpenManager` class. App open ads display when users launch or return to your app, with full support for loading strategies, welcome dialogs, activity exclusion, and single-activity architecture.
|
|
6
|
+
|
|
7
|
+
**Library Version**: v3.3.5
|
|
8
|
+
**Last Updated**: January 2025
|
|
9
|
+
|
|
10
|
+
## What's New in v3.3.5
|
|
11
|
+
|
|
12
|
+
### Loading Strategy Support
|
|
13
|
+
- **Full AdLoadingStrategy Integration**: AppOpenManager now properly uses `appOpenLoadingStrategy` config
|
|
14
|
+
- **ON_DEMAND**: Fetches fresh ads with welcome dialog, uses cached if still fresh
|
|
15
|
+
- **ONLY_CACHE**: Only shows cached ads instantly, silently loads new if unavailable
|
|
16
|
+
- **HYBRID**: Shows cached if available, fetches with dialog otherwise (recommended)
|
|
17
|
+
|
|
18
|
+
### Ad Freshness Tracking
|
|
19
|
+
- **Load Time Tracking**: Cached ads now track when they were loaded
|
|
20
|
+
- **Freshness Threshold**: Configurable `appOpenAdFreshnessThreshold` (default: 4 hours)
|
|
21
|
+
- **Smart Cache Usage**: Prevents wasting pre-loaded ads while ensuring freshness
|
|
22
|
+
|
|
23
|
+
### Auto-Reload Configuration
|
|
24
|
+
- **New Setting**: `appOpenAutoReload` controls automatic reloading after dismissal
|
|
25
|
+
- **Default**: `true` - automatically loads next ad after current one is dismissed
|
|
26
|
+
|
|
27
|
+
### Deprecations
|
|
28
|
+
- **`appOpenFetchFreshAd`**: Deprecated in favor of `appOpenLoadingStrategy`
|
|
29
|
+
- `appOpenFetchFreshAd = true` → `appOpenLoadingStrategy = AdLoadingStrategy.ON_DEMAND`
|
|
30
|
+
- `appOpenFetchFreshAd = false` → `appOpenLoadingStrategy = AdLoadingStrategy.HYBRID`
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
### Basic Setup
|
|
37
|
+
|
|
38
|
+
```kotlin
|
|
39
|
+
class MyApp : Application() {
|
|
40
|
+
private lateinit var appOpenManager: AppOpenManager
|
|
41
|
+
|
|
42
|
+
override fun onCreate() {
|
|
43
|
+
super.onCreate()
|
|
44
|
+
|
|
45
|
+
// Configure loading strategy
|
|
46
|
+
AdManageKitConfig.apply {
|
|
47
|
+
appOpenLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
48
|
+
appOpenAutoReload = true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Set up billing
|
|
52
|
+
BillingConfig.setPurchaseProvider(BillingPurchaseProvider())
|
|
53
|
+
|
|
54
|
+
// Initialize app open manager
|
|
55
|
+
appOpenManager = AppOpenManager(this, "ca-app-pub-xxx/yyy")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That's it! Ads will **automatically load and show** when users open or return to your app.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Loading Strategies
|
|
65
|
+
|
|
66
|
+
Configure via `AdManageKitConfig.appOpenLoadingStrategy`:
|
|
67
|
+
|
|
68
|
+
| Strategy | Behavior | Best For |
|
|
69
|
+
|----------|----------|----------|
|
|
70
|
+
| `ON_DEMAND` | Uses cached if fresh, otherwise fetches with welcome dialog | Maximum coverage |
|
|
71
|
+
| `ONLY_CACHE` | Only shows cached ads instantly, no waiting | Seamless UX |
|
|
72
|
+
| `HYBRID` | Shows cached if available, fetches with dialog if not | Balanced (recommended) |
|
|
73
|
+
|
|
74
|
+
### ON_DEMAND Strategy
|
|
75
|
+
|
|
76
|
+
```kotlin
|
|
77
|
+
AdManageKitConfig.appOpenLoadingStrategy = AdLoadingStrategy.ON_DEMAND
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Behavior:**
|
|
81
|
+
1. If cached ad exists and is fresh (within `appOpenAdFreshnessThreshold`), shows it immediately
|
|
82
|
+
2. If cached ad is stale or doesn't exist, shows welcome dialog and fetches fresh ad
|
|
83
|
+
3. Shows ad when loaded, or continues without ad on timeout/failure
|
|
84
|
+
|
|
85
|
+
### ONLY_CACHE Strategy
|
|
86
|
+
|
|
87
|
+
```kotlin
|
|
88
|
+
AdManageKitConfig.appOpenLoadingStrategy = AdLoadingStrategy.ONLY_CACHE
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Behavior:**
|
|
92
|
+
1. If cached ad exists, shows it immediately
|
|
93
|
+
2. If no cached ad, continues without showing (no waiting)
|
|
94
|
+
3. Silently loads new ad in background for next time
|
|
95
|
+
|
|
96
|
+
### HYBRID Strategy (Recommended)
|
|
97
|
+
|
|
98
|
+
```kotlin
|
|
99
|
+
AdManageKitConfig.appOpenLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Behavior:**
|
|
103
|
+
1. If cached ad exists, shows it immediately
|
|
104
|
+
2. If no cached ad, shows welcome dialog and fetches
|
|
105
|
+
3. Best balance of coverage and user experience
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Configuration
|
|
110
|
+
|
|
111
|
+
### All App Open Settings
|
|
112
|
+
|
|
113
|
+
```kotlin
|
|
114
|
+
AdManageKitConfig.apply {
|
|
115
|
+
// Loading strategy (ON_DEMAND, ONLY_CACHE, HYBRID)
|
|
116
|
+
appOpenLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
117
|
+
|
|
118
|
+
// Freshness threshold - cached ads older than this trigger fresh fetch
|
|
119
|
+
appOpenAdFreshnessThreshold = 4.hours // Google recommends max 4 hours
|
|
120
|
+
|
|
121
|
+
// Auto-reload after ad dismissal
|
|
122
|
+
appOpenAutoReload = true // default: true
|
|
123
|
+
|
|
124
|
+
// Timeout for ad loading
|
|
125
|
+
appOpenAdTimeout = 4.seconds
|
|
126
|
+
|
|
127
|
+
// Welcome dialog customization
|
|
128
|
+
welcomeDialogAppIcon = R.mipmap.ic_launcher
|
|
129
|
+
welcomeDialogTitle = "Welcome Back!"
|
|
130
|
+
welcomeDialogSubtitle = "Loading your content..."
|
|
131
|
+
welcomeDialogFooter = "Just a moment..."
|
|
132
|
+
welcomeDialogDismissDelay = 0.8.seconds
|
|
133
|
+
|
|
134
|
+
// Dialog colors
|
|
135
|
+
dialogOverlayColor = 0x80000000.toInt() // 50% black
|
|
136
|
+
dialogCardBackgroundColor = Color.WHITE
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
### Automatic Display
|
|
145
|
+
|
|
146
|
+
App open ads show automatically when the app comes to foreground:
|
|
147
|
+
|
|
148
|
+
```kotlin
|
|
149
|
+
// Initialize in Application.onCreate()
|
|
150
|
+
appOpenManager = AppOpenManager(this, "ca-app-pub-xxx/yyy")
|
|
151
|
+
// That's it! Ads show automatically
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Force Show
|
|
155
|
+
|
|
156
|
+
```kotlin
|
|
157
|
+
appOpenManager.forceShowAdIfAvailable(activity, object : AdManagerCallback() {
|
|
158
|
+
override fun onNextAction() {
|
|
159
|
+
// Ad dismissed or failed - continue with your flow
|
|
160
|
+
navigateToMain()
|
|
161
|
+
}
|
|
162
|
+
override fun onAdLoaded() {
|
|
163
|
+
// Ad was displayed
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Preload Ad
|
|
169
|
+
|
|
170
|
+
```kotlin
|
|
171
|
+
// Optional: Preload for faster first show
|
|
172
|
+
appOpenManager.fetchAd()
|
|
173
|
+
|
|
174
|
+
// With callback
|
|
175
|
+
appOpenManager.fetchAd(object : AdLoadCallback() {
|
|
176
|
+
override fun onAdLoaded() {
|
|
177
|
+
Log.d("AppOpen", "Ad preloaded and ready")
|
|
178
|
+
}
|
|
179
|
+
override fun onFailedToLoad(error: AdError?) {
|
|
180
|
+
Log.e("AppOpen", "Preload failed: ${error?.message}")
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Prefetch Before External Intent
|
|
186
|
+
|
|
187
|
+
```kotlin
|
|
188
|
+
// Prefetch before launching external activity (camera, share, etc.)
|
|
189
|
+
appOpenManager.prefetchNextAd()
|
|
190
|
+
startActivityForResult(cameraIntent, REQUEST_CODE)
|
|
191
|
+
// Ad will be ready when user returns
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Check Status
|
|
195
|
+
|
|
196
|
+
```kotlin
|
|
197
|
+
// Check if ad is loaded and ready
|
|
198
|
+
if (appOpenManager.isAdAvailable()) {
|
|
199
|
+
// Ad is ready to show
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Check if ad is currently loading
|
|
203
|
+
if (appOpenManager.isAdLoading()) {
|
|
204
|
+
// Ad is being fetched
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Get cached ad age
|
|
208
|
+
val ageMs = appOpenManager.getCachedAdAgeMs()
|
|
209
|
+
if (ageMs > 0) {
|
|
210
|
+
Log.d("AppOpen", "Cached ad is ${ageMs / 1000}s old")
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Skip Next Ad
|
|
215
|
+
|
|
216
|
+
```kotlin
|
|
217
|
+
// Skip the next automatic ad (e.g., after purchase or important action)
|
|
218
|
+
appOpenManager.skipNextAd()
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Activity/Screen Exclusion
|
|
224
|
+
|
|
225
|
+
### Exclude Activities
|
|
226
|
+
|
|
227
|
+
```kotlin
|
|
228
|
+
// Exclude specific activities from showing ads
|
|
229
|
+
appOpenManager.disableAppOpenWithActivity(SplashActivity::class.java)
|
|
230
|
+
appOpenManager.disableAppOpenWithActivity(PaymentActivity::class.java)
|
|
231
|
+
|
|
232
|
+
// Re-enable later if needed
|
|
233
|
+
appOpenManager.includeAppOpenActivityForAds(SplashActivity::class.java)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Single-Activity Architecture (Fragments/Compose)
|
|
237
|
+
|
|
238
|
+
For apps with one activity and multiple screens:
|
|
239
|
+
|
|
240
|
+
```kotlin
|
|
241
|
+
// Set current screen tag when navigating
|
|
242
|
+
navController.addOnDestinationChangedListener { _, destination, _ ->
|
|
243
|
+
appOpenManager.setCurrentScreenTag(destination.label?.toString())
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Exclude specific screens by tag
|
|
247
|
+
appOpenManager.excludeScreenTags("Payment", "Onboarding", "Checkout")
|
|
248
|
+
|
|
249
|
+
// Or use fragment tag provider
|
|
250
|
+
appOpenManager.setFragmentTagProvider {
|
|
251
|
+
supportFragmentManager.fragments.lastOrNull()?.tag
|
|
252
|
+
}
|
|
253
|
+
appOpenManager.excludeFragmentTags("PaymentFragment", "OnboardingFragment")
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Temporary Disable
|
|
257
|
+
|
|
258
|
+
```kotlin
|
|
259
|
+
// Temporarily disable during critical flows
|
|
260
|
+
appOpenManager.disableAppOpenAdsTemporarily()
|
|
261
|
+
// ... perform operation ...
|
|
262
|
+
appOpenManager.enableAppOpenAds()
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Migration from appOpenFetchFreshAd
|
|
268
|
+
|
|
269
|
+
If you were using `appOpenFetchFreshAd`, migrate to `appOpenLoadingStrategy`:
|
|
270
|
+
|
|
271
|
+
```kotlin
|
|
272
|
+
// Before (deprecated)
|
|
273
|
+
AdManageKitConfig.appOpenFetchFreshAd = true // Always fetch fresh
|
|
274
|
+
|
|
275
|
+
// After
|
|
276
|
+
AdManageKitConfig.appOpenLoadingStrategy = AdLoadingStrategy.ON_DEMAND
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```kotlin
|
|
280
|
+
// Before (deprecated)
|
|
281
|
+
AdManageKitConfig.appOpenFetchFreshAd = false // Use cached when available
|
|
282
|
+
|
|
283
|
+
// After
|
|
284
|
+
AdManageKitConfig.appOpenLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## API Reference
|
|
290
|
+
|
|
291
|
+
### AppOpenManager Methods
|
|
292
|
+
|
|
293
|
+
| Method | Description |
|
|
294
|
+
|--------|-------------|
|
|
295
|
+
| `fetchAd()` | Preload ad in background |
|
|
296
|
+
| `fetchAd(callback, timeout, customAdUnitId)` | Preload with options |
|
|
297
|
+
| `showAdIfAvailable()` | Show if cached (lifecycle triggered) |
|
|
298
|
+
| `forceShowAdIfAvailable(activity, callback)` | Force show with callback |
|
|
299
|
+
| `isAdAvailable()` | Check if ad is cached |
|
|
300
|
+
| `isAdLoading()` | Check if ad is being fetched |
|
|
301
|
+
| `getCachedAdAgeMs()` | Get age of cached ad in milliseconds |
|
|
302
|
+
| `prefetchNextAd()` | Prefetch before external intent |
|
|
303
|
+
| `skipNextAd()` | Skip next automatic ad |
|
|
304
|
+
| `disableAppOpenWithActivity(class)` | Exclude activity |
|
|
305
|
+
| `includeAppOpenActivityForAds(class)` | Re-include activity |
|
|
306
|
+
| `setCurrentScreenTag(tag)` | Set current screen for single-activity apps |
|
|
307
|
+
| `excludeScreenTags(vararg tags)` | Exclude screens by tag |
|
|
308
|
+
| `disableAppOpenAdsTemporarily()` | Temporarily disable |
|
|
309
|
+
| `enableAppOpenAds()` | Re-enable after temporary disable |
|
|
310
|
+
|
|
311
|
+
### AdManageKitConfig Settings
|
|
312
|
+
|
|
313
|
+
| Setting | Description | Default |
|
|
314
|
+
|---------|-------------|---------|
|
|
315
|
+
| `appOpenLoadingStrategy` | Loading strategy | `HYBRID` |
|
|
316
|
+
| `appOpenAdFreshnessThreshold` | Max age for "fresh" cached ad | 4 hours |
|
|
317
|
+
| `appOpenAutoReload` | Auto-reload after dismissal | `true` |
|
|
318
|
+
| `appOpenAdTimeout` | Load timeout | 4 seconds |
|
|
319
|
+
| `welcomeDialogAppIcon` | App icon resource | 0 |
|
|
320
|
+
| `welcomeDialogTitle` | Dialog title | "Welcome Back!" |
|
|
321
|
+
| `welcomeDialogSubtitle` | Dialog subtitle | "Loading..." |
|
|
322
|
+
| `welcomeDialogFooter` | Dialog footer | "Just a moment..." |
|
|
323
|
+
| `welcomeDialogDismissDelay` | Delay before dismiss | 0.8 seconds |
|
|
324
|
+
| `dialogOverlayColor` | Overlay color | 50% black |
|
|
325
|
+
| `dialogCardBackgroundColor` | Card background | Theme default |
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Best Practices
|
|
330
|
+
|
|
331
|
+
1. **Initialize in Application** - Set up `AppOpenManager` in `Application.onCreate()`
|
|
332
|
+
2. **Use HYBRID Strategy** - Best balance of coverage and UX
|
|
333
|
+
3. **Set App Icon** - Configure `welcomeDialogAppIcon` for branded welcome dialog
|
|
334
|
+
4. **Exclude Sensitive Screens** - Payment, onboarding, splash screens
|
|
335
|
+
5. **Skip After Important Actions** - Call `skipNextAd()` after purchases
|
|
336
|
+
6. **Prefetch Before External Intents** - Use `prefetchNextAd()` before camera/share
|
|
337
|
+
7. **Wire Billing** - Ensure premium users don't see ads
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Troubleshooting
|
|
342
|
+
|
|
343
|
+
### Ad Not Showing
|
|
344
|
+
|
|
345
|
+
1. **Check availability**: `appOpenManager.isAdAvailable()`
|
|
346
|
+
2. **Check exclusion list**: Is current activity/screen excluded?
|
|
347
|
+
3. **Check purchase status**: `BillingConfig.getPurchaseProvider().isPurchased()`
|
|
348
|
+
4. **Check loading**: `appOpenManager.isAdLoading()`
|
|
349
|
+
|
|
350
|
+
### Stale Ads Showing
|
|
351
|
+
|
|
352
|
+
Reduce the freshness threshold:
|
|
353
|
+
```kotlin
|
|
354
|
+
AdManageKitConfig.appOpenAdFreshnessThreshold = 2.hours
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Ad Not Reloading
|
|
358
|
+
|
|
359
|
+
Check auto-reload setting:
|
|
360
|
+
```kotlin
|
|
361
|
+
AdManageKitConfig.appOpenAutoReload = true
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Strategy Not Working
|
|
365
|
+
|
|
366
|
+
Ensure you're on v3.3.5+ and using `appOpenLoadingStrategy` (not deprecated `appOpenFetchFreshAd`).
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## Firebase Analytics Events
|
|
371
|
+
|
|
372
|
+
AppOpenManager automatically logs these events:
|
|
373
|
+
|
|
374
|
+
| Event | Description |
|
|
375
|
+
|-------|-------------|
|
|
376
|
+
| `ad_impression` | Ad was shown |
|
|
377
|
+
| `ad_paid_event` | Revenue tracking |
|
|
378
|
+
| `ad_failed_to_load` | Load failure with error code |
|
|
379
|
+
| `ad_request` | Ad request initiated |
|
|
380
|
+
| `ad_fill` | Ad successfully loaded |
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Changelog
|
|
385
|
+
|
|
386
|
+
### v3.3.5 (January 2025)
|
|
387
|
+
- Full `AdLoadingStrategy` support (ON_DEMAND, ONLY_CACHE, HYBRID)
|
|
388
|
+
- Ad freshness tracking with `appOpenAdFreshnessThreshold`
|
|
389
|
+
- Auto-reload configuration with `appOpenAutoReload`
|
|
390
|
+
- Deprecated `appOpenFetchFreshAd` in favor of `appOpenLoadingStrategy`
|
|
391
|
+
- Fixed auto-reload after ad dismissal
|
|
392
|
+
|
|
393
|
+
### v3.2.0
|
|
394
|
+
- Single-activity architecture support
|
|
395
|
+
- Screen/fragment tag exclusion
|
|
396
|
+
- Temporary disable/enable
|
|
397
|
+
|
|
398
|
+
### v3.0.0
|
|
399
|
+
- Ad prefetching with `prefetchNextAd()`
|
|
400
|
+
- `isAdLoading()` status check
|
|
401
|
+
|
|
402
|
+
### v2.8.0
|
|
403
|
+
- Welcome dialog with customization
|
|
404
|
+
- Loading strategy configuration
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## References
|
|
409
|
+
|
|
410
|
+
- [AdMob App Open Ads](https://developers.google.com/admob/android/app-open-ads)
|
|
411
|
+
- [GitHub Repository](https://github.com/i2hammad/AdManageKit)
|
|
412
|
+
- [API Documentation](https://i2hammad.github.io/AdManageKit/)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Interstitial Ads · AdManageKit v2.8.0
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`AdManageKit` 2.8.0 ships a complete interstitial stack that spans `AdManager`, the fluent `InterstitialAdBuilder`, and brand-new Jetpack Compose utilities. The stack now includes automatic retry with exponential backoff, lifecycle-safe splash loading, fallback ad units, activity-aware purchase gating, and Compose state helpers. Everything is fully backward compatible with the traditional view-based APIs while enabling declarative use in Compose apps.
|
|
5
|
+
|
|
6
|
+
**What's new in v2.8.0**
|
|
7
|
+
- `forceShowInterstitial()` now respects global loading strategy
|
|
8
|
+
- New `forceShowInterstitialAlways()` for explicit force fetch
|
|
9
|
+
- Global `interstitialAutoReload` config with per-call override
|
|
10
|
+
- All AdManager methods use global auto-reload config as default
|
|
11
|
+
|
|
12
|
+
**What's new in v2.7.0**
|
|
13
|
+
- Smart splash screen with `waitForLoading()` in InterstitialAdBuilder
|
|
14
|
+
- New `isLoading()` and `showOrWaitForAd()` methods
|
|
15
|
+
- Frequency controls: `everyNthTime`, `maxShows`, `minInterval`
|
|
16
|
+
|
|
17
|
+
**What's new since v1.x**
|
|
18
|
+
- Jetpack Compose helpers: `rememberInterstitialAd`, `InterstitialAdEffect`, `rememberInterstitialAdState`
|
|
19
|
+
- Fluent builder with frequency controls (`everyNthTime`, `maxShows`, `minInterval`, `.force()`) and fallback chains
|
|
20
|
+
- Automatic retry via `AdRetryManager` (circuit breaker removed to maximize show rate)
|
|
21
|
+
- Splash-friendly `loadInterstitialAdForSplash(...)` with timeouts and callbacks
|
|
22
|
+
- Debug overlays, aggressive pre-loading helpers, and test-mode overrides wired through `AdManageKitConfig`
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
Add the v2.8.0 artifacts plus Compose (if needed):
|
|
28
|
+
|
|
29
|
+
```groovy
|
|
30
|
+
dependencies {
|
|
31
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit:v2.8.0"
|
|
32
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-core:v2.8.0"
|
|
33
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v2.8.0"
|
|
34
|
+
// Optional – Jetpack Compose helpers:
|
|
35
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v2.8.0"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Configure Once
|
|
42
|
+
Set the new centralized config inside `Application.onCreate()`:
|
|
43
|
+
|
|
44
|
+
```kotlin
|
|
45
|
+
class MyApp : Application() {
|
|
46
|
+
override fun onCreate() {
|
|
47
|
+
super.onCreate()
|
|
48
|
+
|
|
49
|
+
BillingConfig.setPurchaseProvider(BillingPurchaseProvider())
|
|
50
|
+
|
|
51
|
+
AdManageKitConfig.apply {
|
|
52
|
+
debugMode = BuildConfig.DEBUG
|
|
53
|
+
defaultInterstitialInterval = 20.seconds
|
|
54
|
+
autoRetryFailedAds = true
|
|
55
|
+
maxRetryAttempts = 3
|
|
56
|
+
enableAdaptiveIntervals = true
|
|
57
|
+
enablePerformanceMetrics = BuildConfig.DEBUG
|
|
58
|
+
|
|
59
|
+
// Loading strategy (v2.6.0+)
|
|
60
|
+
interstitialLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
61
|
+
|
|
62
|
+
// Auto-reload after showing (v2.8.0+)
|
|
63
|
+
interstitialAutoReload = true // default: true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`AdManageKitConfig` now drives retry timing, adaptive intervals, loading strategy, auto-reload, analytics, and debug overlays for every interstitial entry-point.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Option 1 · Direct `AdManager`
|
|
74
|
+
|
|
75
|
+
`AdManager` lives in `com.i2hammad.admanagekit.admob` and exposes imperative control with smart defaults.
|
|
76
|
+
|
|
77
|
+
```kotlin
|
|
78
|
+
private val adManager = AdManager.getInstance()
|
|
79
|
+
|
|
80
|
+
fun preloadInterstitial(activity: Activity) {
|
|
81
|
+
adManager.loadInterstitialAd(activity, AD_UNIT_INTERSTITIAL)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fun showInterstitial(activity: Activity) {
|
|
85
|
+
adManager.showInterstitialAdByTime(activity, object : AdManagerCallback() {
|
|
86
|
+
override fun onNextAction() {
|
|
87
|
+
navigateNext()
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Key APIs
|
|
94
|
+
- `loadInterstitialAdForSplash(context, unit, timeoutMs, callback)` – timeouts + callback chain for splash flows
|
|
95
|
+
- `forceShowInterstitial(activity, callback)` – respects loading strategy (v2.8.0+)
|
|
96
|
+
- `forceShowInterstitialAlways(activity, callback)` – always force fetch (bypasses strategy, v2.8.0+)
|
|
97
|
+
- `showInterstitialIfReady(activity, callback, reloadAd)` – show only if cached
|
|
98
|
+
- `showInterstitialAdByTime(...)` & `showInterstitialAdByCount(...)` – throttle via interval or count
|
|
99
|
+
- `forceShowInterstitialWithDialog(...)` – built-in loading dialog for smoother UX
|
|
100
|
+
- `showOrWaitForAd(activity, callback, timeout, showDialog)` – smart splash screen method (v2.7.0+)
|
|
101
|
+
- `isLoading()` – check if ad is currently loading (v2.7.0+)
|
|
102
|
+
- `preloadAd(context, adUnitId)` – kicks off background loading for next screen
|
|
103
|
+
- `enableAggressiveAdLoading()` / `resetAdThrottling()` – quick helpers for tuning show rate
|
|
104
|
+
|
|
105
|
+
### Advanced Behavior
|
|
106
|
+
- **Purchase-aware**: `BillingConfig` short-circuits loading/showing when a user owns the IAP/subscription.
|
|
107
|
+
- **Auto retry**: Failed loads automatically use `AdRetryManager` with exponential backoff based on `AdManageKitConfig`.
|
|
108
|
+
- **Analytics**: All impressions, failures, dismissals, and paid events are logged through Firebase Analytics when configured.
|
|
109
|
+
|
|
110
|
+
### Splash Screen Example
|
|
111
|
+
```kotlin
|
|
112
|
+
AdManager.getInstance().loadInterstitialAdForSplash(
|
|
113
|
+
context = this,
|
|
114
|
+
adUnitId = getString(R.string.interstitial_splash),
|
|
115
|
+
timeoutMillis = 7_000,
|
|
116
|
+
callback = object : AdManagerCallback() {
|
|
117
|
+
override fun onAdLoaded() { startMainFlow() }
|
|
118
|
+
override fun onFailedToLoad(error: AdError?) { startMainFlow() }
|
|
119
|
+
override fun onNextAction() { startMainFlow() }
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Option 2 · `InterstitialAdBuilder`
|
|
127
|
+
|
|
128
|
+
The builder (also under `admob`) wraps `AdManager` with a fluent API, fallback chains, loading dialogs, and frequency controls.
|
|
129
|
+
|
|
130
|
+
```kotlin
|
|
131
|
+
InterstitialAdBuilder.with(this)
|
|
132
|
+
.adUnit(getString(R.string.interstitial_home))
|
|
133
|
+
.fallbacks(
|
|
134
|
+
getString(R.string.interstitial_backup_a),
|
|
135
|
+
getString(R.string.interstitial_backup_b)
|
|
136
|
+
)
|
|
137
|
+
.everyNthTime(2) // show every 2nd invocation
|
|
138
|
+
.maxShows(12) // cap session exposure
|
|
139
|
+
.minIntervalSeconds(45) // respect UX
|
|
140
|
+
.withLoadingDialog()
|
|
141
|
+
.onAdShown { analytics.logEvent("interstitial_shown", null) }
|
|
142
|
+
.onFailed { error -> Log.w("Ads", "Failed: ${error.message}") }
|
|
143
|
+
.show { continueToNextScreen() }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Highlights
|
|
147
|
+
- `.everyNthTime(n)` – enforce cadence per trigger point
|
|
148
|
+
- `.maxShows(count)` – share the global `AdManager` counter to cap exposure
|
|
149
|
+
- `.minInterval(millis)` / `.minIntervalSeconds(seconds)` – override global interval without touching config
|
|
150
|
+
- `.force()` or `.respectInterval(false)` – bypass timers when needed (e.g., exit flows)
|
|
151
|
+
- `.fallback()` / `.fallbacks()` – try multiple ad units automatically
|
|
152
|
+
- `.preload()` – warm up future screens without showing
|
|
153
|
+
|
|
154
|
+
Builder callbacks have Java-friendly interfaces (`OnAdCompleteListener`, `OnAdShownListener`, etc.), so the same API works across Kotlin and Java modules.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Option 3 · Jetpack Compose
|
|
159
|
+
|
|
160
|
+
The Compose module brings stateful helpers that wrap the same business logic.
|
|
161
|
+
|
|
162
|
+
```kotlin
|
|
163
|
+
@Composable
|
|
164
|
+
fun ContentWithInterstitial() {
|
|
165
|
+
val showAd = rememberInterstitialAd(
|
|
166
|
+
adUnitId = stringResource(R.string.interstitial_feed),
|
|
167
|
+
preloadAd = true,
|
|
168
|
+
onAdShown = { analytics.logEvent("feed_interstitial_shown", null) },
|
|
169
|
+
onAdDismissed = { navigateNext() },
|
|
170
|
+
onAdFailedToLoad = { reason -> Log.w("Ads", reason) }
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
Button(onClick = showAd) {
|
|
174
|
+
Text("Open next article")
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Additional helpers:
|
|
180
|
+
|
|
181
|
+
| Helper | Purpose |
|
|
182
|
+
|--------|---------|
|
|
183
|
+
| `InterstitialAdEffect(adUnitId, showMode, maxDisplayCount)` | Declarative effect that respects TIME / COUNT / FORCE modes. |
|
|
184
|
+
| `rememberInterstitialAdState(adUnitId)` | Mutable state holder exposing `isLoaded`, `loadAd()`, `showAdByTime()`, `forceShowAd()` for custom UI flows. |
|
|
185
|
+
| `AdManageKitInitEffect()` | Initializes NativeAdManager/FirebaseAnalytics inside Compose entry points so cache stats stay accurate. |
|
|
186
|
+
|
|
187
|
+
Compose helpers automatically reload on lifecycle events and integrate with `BillingConfig` purchase checks.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Advanced Controls
|
|
192
|
+
|
|
193
|
+
- **Retry Tuning** – `AdManageKitConfig.autoRetryFailedAds`, `maxRetryAttempts`, `baseRetryDelay`, `maxRetryDelay`, and `enableExponentialBackoff` control how `AdRetryManager` behaves per ad unit.
|
|
194
|
+
- **Aggressive Mode** – call `AdManager.enableAggressiveAdLoading()` during experiments to drop the interval to 5 seconds, then `resetAdThrottling()` before going live.
|
|
195
|
+
- **Debug Overlay** – enable via `AdManageKitConfig.debugMode = true` and `AdDebugUtils.enableDebugOverlay(activity, true)` to inspect attempts, cache hits, and paid events in-app.
|
|
196
|
+
- **Testing** – set `AdManageKitConfig.testMode = true` or map production IDs to test IDs with `AdDebugUtils.setTestAdUnits(mapOf(prodId to testId))`.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## API Cheat Sheet
|
|
201
|
+
|
|
202
|
+
| API | Description |
|
|
203
|
+
|-----|-------------|
|
|
204
|
+
| `AdManager.loadInterstitialAd(context, adUnitId)` | Preloads and caches one interstitial per unit. |
|
|
205
|
+
| `AdManager.loadInterstitialAd(context, unit, callback)` | Same as above but surfaces `InterstitialAdLoadCallback`. |
|
|
206
|
+
| `AdManager.loadInterstitialAdForSplash(...)` | Splash-friendly load with timeout + callback. |
|
|
207
|
+
| `AdManager.forceShowInterstitial(activity, callback)` | Respects loading strategy (v2.8.0+). |
|
|
208
|
+
| `AdManager.forceShowInterstitialAlways(activity, callback)` | Always force fetch, bypasses strategy (v2.8.0+). |
|
|
209
|
+
| `AdManager.showInterstitialIfReady(activity, callback, reloadAd)` | Show only if cached. |
|
|
210
|
+
| `AdManager.showInterstitialAdByTime` / `showInterstitialAdByCount` | Throttle via time interval or count. |
|
|
211
|
+
| `AdManager.forceShowInterstitialWithDialog` | Uses built-in dialog, respects strategy. |
|
|
212
|
+
| `AdManager.showOrWaitForAd(...)` | Smart splash screen method (v2.7.0+). |
|
|
213
|
+
| `AdManager.isLoading()` | Check if ad is currently loading (v2.7.0+). |
|
|
214
|
+
| `AdManager.preloadAd` / `resetAdThrottling` / `enableAggressiveAdLoading` | Utility helpers for show-rate tuning. |
|
|
215
|
+
| `InterstitialAdBuilder.with(activity)` | Entry point for the fluent API (Kotlin + Java). |
|
|
216
|
+
| `InterstitialAdBuilder.autoReload(Boolean)` | Override global auto-reload setting (v2.8.0+). |
|
|
217
|
+
| `InterstitialAdBuilder.waitForLoading()` | Smart splash screen behavior (v2.7.0+). |
|
|
218
|
+
| `rememberInterstitialAd`, `InterstitialAdEffect`, `rememberInterstitialAdState` | Compose-first APIs for declarative UI. |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Best Practices
|
|
223
|
+
|
|
224
|
+
- **Configure once** in `Application` and rely on builder/Compose APIs per screen—don’t sprinkle config logic in activities.
|
|
225
|
+
- **Always preload** on the previous screen (builder `.preload()` or `AdManager.preloadAd`) for maximum fill rate.
|
|
226
|
+
- **Use frequency controls** (`everyNthTime`, `maxShows`, `minInterval`) plus `AdManageKitConfig.defaultInterstitialInterval` to protect UX.
|
|
227
|
+
- **Respect purchases** by always wiring a `BillingPurchaseProvider` before loading—`AdManager` skips ads automatically.
|
|
228
|
+
- **Enable debug overlay** in QA builds to verify retries, cache state, and paid events before shipping.
|
|
229
|
+
|
|
230
|
+
With these updates, interstitial integration stays identical for legacy XML screens, gains new fluent APIs for Java/Kotlin, and becomes fully declarative in Compose-heavy codebases—all powered by the same resilient core.
|
|
231
|
+
|
|
232
|
+
## Best Practices
|
|
233
|
+
- **Purchase Integration**: Ensure `BillingConfig.setPurchaseProvider` is called in your `Application` class to respect in-app purchases.
|
|
234
|
+
- **Ad Frequency**: Use `setAdInterval` or `showInterstitialAdByCount` to avoid overwhelming users with frequent ads.
|
|
235
|
+
- **Dialog Usage**: Use `forceShowInterstitialWithDialog` for smoother transitions in critical flows (e.g., activity changes).
|
|
236
|
+
- **Error Handling**: Implement `AdManagerCallback` and `InterstitialAdLoadCallback` to handle load/display failures gracefully.
|
|
237
|
+
- **Testing**:
|
|
238
|
+
- Test with AdMob test IDs (e.g., `ca-app-pub-3940256099942544/1033173712`).
|
|
239
|
+
- Verify time-based and count-based triggers.
|
|
240
|
+
- Test purchase scenarios to ensure ads are skipped for premium users.
|
|
241
|
+
- **Analytics**: Review Firebase Analytics logs to monitor ad performance and errors.
|
|
242
|
+
|
|
243
|
+
## Limitations
|
|
244
|
+
- **Single Ad Cache**: Only one interstitial ad is cached at a time per `AdManager` instance.
|
|
245
|
+
- **Manual Frequency Control**: Time and count limits are managed manually; adjust `adIntervalMillis` or `maxDisplayCount` as needed.
|
|
246
|
+
- **Dialog Dependency**: The loading dialog requires Material Components; ensure it’s included in your app.
|
|
247
|
+
|
|
248
|
+
## Dependencies
|
|
249
|
+
- **Google AdMob SDK**: For ad loading and display.
|
|
250
|
+
- **Firebase Analytics**: For logging ad events.
|
|
251
|
+
- **Material Components**: For loading dialogs.
|
|
252
|
+
- **Project Resources**: `BillingConfig` for purchase checks.
|
|
253
|
+
|
|
254
|
+
## Troubleshooting
|
|
255
|
+
- **Ad Not Loading**: Verify `adUnitId`, network connectivity, and AdMob configuration.
|
|
256
|
+
- **Ad Not Displaying**: Check `isReady()` and ensure the user hasn’t purchased the app.
|
|
257
|
+
- **Dialog Issues**: Ensure Material Components are included and the activity isn’t finishing.
|
|
258
|
+
- **Analytics Missing**: Confirm Firebase is initialized and configured.
|
|
259
|
+
|
|
260
|
+
## Future Improvements
|
|
261
|
+
- Support for preloading multiple interstitial ads.
|
|
262
|
+
- Configurable dialog duration and styling.
|
|
263
|
+
- Automatic frequency optimization based on user engagement.
|
|
264
|
+
|
|
265
|
+
## References
|
|
266
|
+
- [AdMob Interstitial Ads Documentation](https://developers.google.com/admob/android/interstitial)
|
|
267
|
+
- [Firebase Analytics Documentation](https://firebase.google.com/docs/analytics)
|
|
268
|
+
- [AdManageKit v2.5.0 Release Notes](../RELEASE_NOTES_v2.5.0.md)
|
|
269
|
+
- [Native Ads Caching Wiki](native-ads-caching.md)
|