admanagekit-mcp-server 1.2.0 → 1.2.2
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 +18 -9
- package/content/docs/AD_LOADING_STRATEGIES.md +34 -3
- package/content/docs/APP_PURCHASE_GUIDE.md +18 -0
- package/content/docs/COMPOSE_INTEGRATION.md +79 -5
- package/content/docs/NATIVE_AD_PRELOADING.md +5 -2
- package/content/docs/NATIVE_TEMPLATE_VIEW.md +7 -3
- package/content/docs/release-notes/RELEASE_NOTES_v4.4.1.md +110 -0
- package/content/docs/release-notes/RELEASE_NOTES_v4.4.2.md +121 -0
- package/content/docs/release-notes/RELEASE_NOTES_v4.4.3.md +121 -0
- package/content/wiki/Ad-Loading-Strategies.md +26 -8
- package/content/wiki/App-Open-Ads.md +5 -5
- package/content/wiki/Banner-Ads.md +4 -4
- package/content/wiki/Billing-Integration.md +20 -2
- package/content/wiki/Configuration.md +25 -1
- package/content/wiki/Home.md +70 -18
- package/content/wiki/Interstitial-Ads.md +9 -6
- package/content/wiki/Jetpack-Compose.md +26 -5
- package/content/wiki/Multi-Provider-Waterfall.md +4 -4
- package/content/wiki/NativeAdManager.md +38 -9
- package/content/wiki/Yandex-Integration.md +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Release Notes — v4.4.3
|
|
2
|
+
|
|
3
|
+
**Release Date:** 2026-08-15
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
v4.4.3 is a bug-fix and dependency release. No API was added, removed or changed. Two of the fixes are silent-failure bugs that cost real money:
|
|
8
|
+
|
|
9
|
+
- **A rewarded load the manager had given up on could sabotage the load that replaced it** — throwing away an ad that had just arrived, and clearing the "loading" flag out from under a request that was still running.
|
|
10
|
+
- **Billing could stop acknowledging purchases for the rest of the process**, which lets Play auto-refund a completed purchase on day 3.
|
|
11
|
+
|
|
12
|
+
It also picks up the Next-Gen GMA SDK **1.3.1**, Yandex Mobile Ads **8.3.0**, and refreshed AndroidX/Firebase/Compose BOMs.
|
|
13
|
+
|
|
14
|
+
Upgrading is a drop-in from 4.4.x.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Fixed
|
|
19
|
+
|
|
20
|
+
### A timed-out rewarded load could sabotage the one that replaced it
|
|
21
|
+
|
|
22
|
+
`RewardedAdManager.loadRewardedAdWithTimeout(...)` stops waiting for a load once its timeout elapses — but a request handed to the SDK **cannot be cancelled**, so it keeps running and reports back whenever it finishes. Its callbacks then ran the full success/failure path as though they still spoke for the manager, even though a replacement load had started in the meantime.
|
|
23
|
+
|
|
24
|
+
Concretely, a late callback from an abandoned request could:
|
|
25
|
+
|
|
26
|
+
- **Throw away a perfectly good ad.** The failure path ran `rewardedAd = null` unconditionally, so a stale failure discarded an ad a *later* load had just delivered. The next `showAd()` found nothing and skipped the reward.
|
|
27
|
+
- **Clear `isLoading` out from under the load that was still running**, so the manager reported itself idle while a request was in flight — letting a duplicate load start and burning an extra ad request.
|
|
28
|
+
- **Fail callers queued behind a load that had not finished yet**, via `notifyPendingLoadFailure`.
|
|
29
|
+
- **Schedule a retry for a request nobody was waiting on.**
|
|
30
|
+
|
|
31
|
+
Every load path now claims a generation token and checks it before touching anything shared — the same mechanism `RewardedWaterfall` already used internally. A stale callback answers *its own* caller (which is still owed a result and has no other source of one) and otherwise leaves shared state alone.
|
|
32
|
+
|
|
33
|
+
A late ad is **kept rather than dropped**: it is real and showable no matter which request produced it, so it is adopted for the next show whenever nothing better is already in hand. This applies to both the AdMob path and the waterfall path.
|
|
34
|
+
|
|
35
|
+
Two related unconditional writes were tightened at the same time:
|
|
36
|
+
|
|
37
|
+
- The direct load's failure path no longer does `rewardedAd = null` at all. A failed request means *this* request produced nothing — not that an ad obtained elsewhere has stopped being showable.
|
|
38
|
+
- The waterfall failure path now clears `rewardedWaterfall` only when the chain being reported on is still the one it installed (`if (rewardedWaterfall === waterfall)`), so a newer load's chain — or a late chain adopted in the meantime — is not discarded by an older failure.
|
|
39
|
+
|
|
40
|
+
> This is the same class of bug as the v4.4.2 `AdManager` duplicate-callback fix, in the one manager that still resolved in-flight state with plain flags.
|
|
41
|
+
|
|
42
|
+
### Billing could stop acknowledging purchases for the rest of the process
|
|
43
|
+
|
|
44
|
+
`AppPurchase` gated every re-query on `isServiceConnected`, an `AtomicBoolean` written **only** by `onBillingSetupFinished` and cleared by `onBillingServiceDisconnected`.
|
|
45
|
+
|
|
46
|
+
The library enables `enableAutoServiceReconnection()`, and the SDK restores the connection on its own without necessarily re-firing `onBillingSetupFinished`. So after a single disconnect the flag could stay `false` permanently — while the client itself was perfectly ready — silently disabling:
|
|
47
|
+
|
|
48
|
+
- `verifyPurchased(...)` and `updatePurchaseStatus()` — entitlement re-checks
|
|
49
|
+
- `refreshPurchases(...)` — including **the acknowledgment retry**
|
|
50
|
+
- `consumePurchase(...)`, `queryProductDetails(...)`
|
|
51
|
+
- `connectToGooglePlayBilling()`, which skipped reconnecting because it believed it was still connected
|
|
52
|
+
|
|
53
|
+
That last one matters most: **Play auto-refunds any purchase left unacknowledged for 3 days.** A user who bought while the flag was stuck could be charged, granted the entitlement, and then silently refunded — with the app still treating them as a paying customer.
|
|
54
|
+
|
|
55
|
+
All of these now consult the client's own live state (`billingClient.isReady()`) instead of the latched flag. `onBillingServiceDisconnected` also stops clearing `isBillingAvailable`: the client *was* set up successfully, and `isAvailable()` ANDs that fact with the live readiness check, so it now reports `false` only while the service is actually down rather than latching `false` for the rest of the process.
|
|
56
|
+
|
|
57
|
+
### Acknowledgment required the purchase to match a configured product id
|
|
58
|
+
|
|
59
|
+
In both `verifyPurchased(...)` and `updatePurchaseStatus()`, `acknowledgePurchaseIfNeeded(purchase)` was called *inside* the loop that matched the purchase against `inAppProductIdList` / `subProductIdList`. A `PURCHASED` order whose id the current build does not list was never acknowledged — and so was auto-refunded on day 3.
|
|
60
|
+
|
|
61
|
+
That is not a hypothetical set: promo-code grants, products dropped from a newer release, a Play Console id typo, and a user who purchased on a build that configured more ids than the one they are running now all land here.
|
|
62
|
+
|
|
63
|
+
Acknowledgment now happens **before** the id match, unconditionally for every `PURCHASED` purchase. Entitlement still requires a configured id — only the acknowledgment was decoupled, since the 3-day clock does not care whether your build recognises the product.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Dependencies
|
|
68
|
+
|
|
69
|
+
| Dependency | 4.4.2 | 4.4.3 |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| Google Mobile Ads Next-Gen SDK | 1.3.0 | **1.3.1** |
|
|
72
|
+
| Yandex Mobile Ads | 8.2.0 | **8.3.0** |
|
|
73
|
+
| Compose BOM | 2026.06.01 | **2026.08.00** |
|
|
74
|
+
| Firebase BOM | 34.15.0 | **34.17.0** |
|
|
75
|
+
| AndroidX AppCompat | 1.7.1 | **1.8.0** |
|
|
76
|
+
| ConstraintLayout | 2.2.1 | **2.2.2** |
|
|
77
|
+
| org.json (test only) | 20250517 | **20260719** |
|
|
78
|
+
|
|
79
|
+
Google Play Billing stays at **9.1.0** and Kotlin at **2.2.10**.
|
|
80
|
+
|
|
81
|
+
### Sample app now compiles at JVM 17
|
|
82
|
+
|
|
83
|
+
The `app` sample module was the only module still pinned to `jvmTarget = "1.8"`, while all five published modules use 17. Compose BOM 2026.08.00 ships artifacts compiled at JVM 11+, which cannot be inlined into 1.8 bytecode — so the bump broke `assembleDebug` on the sample with `Cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8`.
|
|
84
|
+
|
|
85
|
+
The sample now uses `VERSION_17` / `jvmTarget = "17"`, matching the library modules. **This does not affect the published artifacts** — their compile options were already 17 and are unchanged. It is noted here only because anyone building the repo from source would otherwise hit it.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
`docs/APP_PURCHASE_GUIDE.md` now documents what pending purchases require from the host app. A pending order (cash, bank transfer, parental approval) can complete hours or days later while the app is closed; `onPurchasesUpdated` only fires if the app happens to be running, so Play requires apps to re-query owned purchases on every foreground. `AppPurchase` queries on billing init, and if the process survives the transition that never runs again — so the guide now shows calling `refreshPurchases()` from the main activity's `onResume()`, and explains that this is what stops a completed pending order from being auto-cancelled on day 3.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Verification
|
|
96
|
+
|
|
97
|
+
`assembleDebug` succeeds and `testDebugUnitTest --rerun-tasks` passes **176 tests, 0 failures** — 173 existing plus 3 new `RewardedAdManagerStaleLoadTest` cases pinning down the stale-load contract:
|
|
98
|
+
|
|
99
|
+
- an abandoned load's failure must not discard an ad another load produced
|
|
100
|
+
- an abandoned load's failure must not clear the replacement's `isLoading`
|
|
101
|
+
- an ad arriving after the timeout is kept for the next show rather than dropped
|
|
102
|
+
|
|
103
|
+
The tests drive the waterfall path, whose providers are fakes the test can complete by hand; the AdMob path runs the same generation checks over a static SDK entry point.
|
|
104
|
+
|
|
105
|
+
The billing changes are **not** covered by automated tests — both depend on `BillingClient` connection-state transitions that the existing `ProductDetailsFactory`-based harness cannot drive. They were verified by reading every call site of `isServiceConnected` and every `acknowledgePurchaseIfNeeded` path; on-device verification against a Play test track is recommended.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Upgrading
|
|
110
|
+
|
|
111
|
+
Drop-in from 4.4.x. No source changes required.
|
|
112
|
+
|
|
113
|
+
If your app relies on pending purchases, add the `onResume()` refresh described under [Documentation](#documentation) — the library cannot do this for you, since it does not own your activity lifecycle.
|
|
114
|
+
|
|
115
|
+
```groovy
|
|
116
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
117
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.3'
|
|
118
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
119
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v4.4.3'
|
|
120
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:v4.4.3'
|
|
121
|
+
```
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Ad Loading Strategies - AdManageKit
|
|
1
|
+
# Ad Loading Strategies - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
AdManageKit v2.6.0+ introduces
|
|
5
|
+
AdManageKit v2.6.0+ introduces four loading strategies that control how ads are fetched and displayed. Choose the right strategy based on your app's needs for user experience vs. ad coverage.
|
|
6
6
|
|
|
7
7
|
## Strategy Types
|
|
8
8
|
|
|
@@ -63,15 +63,33 @@ AdManageKitConfig.interstitialLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
|
63
63
|
- Default recommendation
|
|
64
64
|
- Balanced UX and coverage
|
|
65
65
|
|
|
66
|
+
### 4. FRESH_WITH_CACHE_FALLBACK
|
|
67
|
+
|
|
68
|
+
**Fetch fresh first, fall back to cache on failure**
|
|
69
|
+
|
|
70
|
+
```kotlin
|
|
71
|
+
AdManageKitConfig.nativeLoadingStrategy = AdLoadingStrategy.FRESH_WITH_CACHE_FALLBACK
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Pros | Cons |
|
|
75
|
+
|------|------|
|
|
76
|
+
| Freshest creative when the network cooperates | Slower than cache-first when the fetch is slow |
|
|
77
|
+
| Cache covers the failure case | Requires a warm cache to help |
|
|
78
|
+
| Successful loads are cached for later | - |
|
|
79
|
+
|
|
80
|
+
**Best for:**
|
|
81
|
+
- RecyclerView / feed scenarios where each item should try for a fresh ad
|
|
82
|
+
- Placements where creative freshness matters more than instant fill
|
|
83
|
+
|
|
66
84
|
## Strategy Availability
|
|
67
85
|
|
|
68
|
-
| Ad Type | ON_DEMAND | ONLY_CACHE | HYBRID |
|
|
69
|
-
|
|
70
|
-
| Interstitial | ✅ | ✅ | ✅ |
|
|
71
|
-
| App Open | ✅ | ✅ | ✅ |
|
|
72
|
-
| Native | ✅ |
|
|
86
|
+
| Ad Type | ON_DEMAND | ONLY_CACHE | HYBRID | FRESH_WITH_CACHE_FALLBACK |
|
|
87
|
+
|---------|-----------|------------|--------|---------------------------|
|
|
88
|
+
| Interstitial | ✅ | ✅ | ✅ | ✅ |
|
|
89
|
+
| App Open | ✅ | ✅ | ✅ | ✅ |
|
|
90
|
+
| Native | ✅ | ✅ | ✅ | ✅ |
|
|
73
91
|
|
|
74
|
-
> **Note:** Native ads use shimmer instead of dialog, so ONLY_CACHE hides container
|
|
92
|
+
> **Note:** Native ads use shimmer instead of a dialog, so `ONLY_CACHE` hides the container when nothing is cached rather than blocking the UI.
|
|
75
93
|
|
|
76
94
|
## Configuration
|
|
77
95
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# App Open Ads - AdManageKit v4.3
|
|
1
|
+
# App Open Ads - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
5
|
AdManageKit provides lifecycle-aware app open ad management through `AppOpenManager`. App open ads display when users launch or return to your app, with support for loading strategies, ad freshness enforcement, welcome dialogs, activity/screen exclusion, and the multi-provider waterfall.
|
|
6
6
|
|
|
7
|
-
**Library Version**: v4.3
|
|
7
|
+
**Library Version**: v4.4.3
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -23,9 +23,9 @@ AdManageKit provides lifecycle-aware app open ad management through `AppOpenMana
|
|
|
23
23
|
|
|
24
24
|
```groovy
|
|
25
25
|
dependencies {
|
|
26
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.3
|
|
27
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.3
|
|
28
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.3
|
|
26
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
27
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.3'
|
|
28
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Banner Ads - AdManageKit v4.3
|
|
1
|
+
# Banner Ads - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
5
|
AdManageKit provides `BannerAdView` for banner ad integration with every standard AdMob size, adaptive banners, collapsible banners, a size-aware loading shimmer, auto-refresh, and smart retry logic.
|
|
6
6
|
|
|
7
|
-
**Library Version**: v4.3
|
|
7
|
+
**Library Version**: v4.4.3
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -23,8 +23,8 @@ AdManageKit provides `BannerAdView` for banner ad integration with every standar
|
|
|
23
23
|
|
|
24
24
|
```groovy
|
|
25
25
|
dependencies {
|
|
26
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.3
|
|
27
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.3
|
|
26
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
27
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -7,8 +7,8 @@ AdManageKit provides a comprehensive billing integration module (`admanagekit-bi
|
|
|
7
7
|
### 1. Add Dependency
|
|
8
8
|
|
|
9
9
|
```groovy
|
|
10
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.
|
|
11
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.
|
|
10
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.3'
|
|
11
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
### 2. Define Products
|
|
@@ -52,6 +52,24 @@ class MyApp : Application() {
|
|
|
52
52
|
> Only `PurchaseState.PURCHASED` grants entitlement (pending purchases do not).
|
|
53
53
|
> Consumables still require a manual `consumePurchase(productId)` after granting.
|
|
54
54
|
|
|
55
|
+
> **Pending purchases need one thing from you (v4.4.3).** A pending order (cash,
|
|
56
|
+
> bank transfer, parental approval) can complete hours or days later, while your
|
|
57
|
+
> app is closed. `onPurchasesUpdated` only fires if the app happens to be
|
|
58
|
+
> running, so Play requires apps to re-query owned purchases on every foreground.
|
|
59
|
+
> `AppPurchase` queries on billing init; if your process stays alive across the
|
|
60
|
+
> transition, that never runs again — so call `refreshPurchases()` from your main
|
|
61
|
+
> activity's `onResume()`:
|
|
62
|
+
>
|
|
63
|
+
> ```kotlin
|
|
64
|
+
> override fun onResume() {
|
|
65
|
+
> super.onResume()
|
|
66
|
+
> AppPurchase.getInstance().refreshPurchases()
|
|
67
|
+
> }
|
|
68
|
+
> ```
|
|
69
|
+
>
|
|
70
|
+
> It acknowledges every unacknowledged `PURCHASED` purchase it finds, which is
|
|
71
|
+
> what stops a completed pending order from being auto-cancelled on day 3.
|
|
72
|
+
|
|
55
73
|
### 4. Make Purchases
|
|
56
74
|
|
|
57
75
|
```kotlin
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Configuration - AdManageKit
|
|
1
|
+
# Configuration - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
@@ -32,6 +32,8 @@ class MyApp : Application() {
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
> **Since 4.2.0 you must also call `MobileAds.initialize()` yourself**, before any ad request — the Next-Gen SDK removed the legacy SDK's silent lazy-init. `AdManageKitConfig` only configures this library's behavior; it does not initialize the ads SDK. See [[Home]] for the initialization pattern.
|
|
36
|
+
|
|
35
37
|
## All Configuration Options
|
|
36
38
|
|
|
37
39
|
### Performance Settings
|
|
@@ -138,6 +140,28 @@ AdManageKitConfig.apply {
|
|
|
138
140
|
}
|
|
139
141
|
```
|
|
140
142
|
|
|
143
|
+
### Native Ad Settings
|
|
144
|
+
|
|
145
|
+
| Setting | Description | Default |
|
|
146
|
+
|---------|-------------|---------|
|
|
147
|
+
| `nativeLoadingStrategy` | Loading strategy | HYBRID |
|
|
148
|
+
| `nativeCacheExpiry` | Cache expiry for native ads | 1 hour |
|
|
149
|
+
| `defaultNativeMediaAspect` | Media aspect-ratio hint sent with every native request (v4.3.3+) | ANY |
|
|
150
|
+
| `nativeVideoStartMuted` | Start video creatives muted (v4.3.3+) | true |
|
|
151
|
+
| `nativeVideoClickToExpand` | Allow click-to-expand on video creatives (v4.3.3+) | false |
|
|
152
|
+
| `nativeVideoCustomControls` | Request custom video controls (v4.3.3+) | false |
|
|
153
|
+
|
|
154
|
+
`NativeMediaAspect` values: `UNSPECIFIED`, `ANY`, `LANDSCAPE`, `PORTRAIT`, `SQUARE`. `NativeTemplateView.setMediaAspect(...)` overrides the global default per view.
|
|
155
|
+
|
|
156
|
+
```kotlin
|
|
157
|
+
AdManageKitConfig.apply {
|
|
158
|
+
nativeLoadingStrategy = AdLoadingStrategy.HYBRID
|
|
159
|
+
nativeCacheExpiry = 1.hours
|
|
160
|
+
defaultNativeMediaAspect = NativeMediaAspect.ANY
|
|
161
|
+
nativeVideoStartMuted = true
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
141
165
|
### App Open Settings
|
|
142
166
|
|
|
143
167
|
| Setting | Description | Default |
|
package/content/wiki/Home.md
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
# AdManageKit
|
|
2
2
|
|
|
3
3
|
[](https://jitpack.io/#i2hammad/AdManageKit)
|
|
4
|
-

|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
AdManageKit is a comprehensive Android library designed to simplify the integration and management of Google AdMob ads, Google Play Billing, and User Messaging Platform (UMP) consent.
|
|
8
8
|
|
|
9
|
-
**Latest Version: `
|
|
9
|
+
**Latest Version: `4.4.3`**
|
|
10
10
|
|
|
11
|
-
## What's New in
|
|
11
|
+
## What's New in 4.4.3
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
13
|
+
Bug-fix and dependency release, no API changes. Two silent-failure bugs, both of which cost money.
|
|
14
|
+
|
|
15
|
+
- **A timed-out rewarded load could sabotage the one that replaced it** — a request handed to the SDK cannot be cancelled, and when it finally reported back it could discard an ad a *newer* load had just delivered, clear the loading flag out from under a request still in flight, and fail callers waiting on a load that had not finished. Every load path now carries a generation token, and a late ad is kept for the next show instead of dropped
|
|
16
|
+
- **Billing could stop acknowledging purchases for the rest of the process** — the connection flag could latch `false` after one disconnect while the client was actually ready, disabling every purchase re-query including the acknowledgment retry. Play auto-refunds an unacknowledged purchase after 3 days
|
|
17
|
+
- **Acknowledgment no longer requires a configured product id** — a `PURCHASED` order the current build does not list (promo grants, dropped products, a Console typo) was never acknowledged, and so was auto-refunded on day 3
|
|
18
|
+
- **Dependencies** — Next-Gen GMA SDK 1.3.1, Yandex Mobile Ads 8.3.0, Compose BOM 2026.08.00, Firebase BOM 34.17.0, AppCompat 1.8.0
|
|
19
|
+
|
|
20
|
+
> **Pending purchases need one thing from your app:** call `refreshPurchases()` from your main activity's `onResume()`. See [[Billing Integration]].
|
|
21
|
+
|
|
22
|
+
## Recent Highlights
|
|
23
|
+
|
|
24
|
+
- **4.4.2** — Rewarded callbacks marshalled to the main thread (they could crash the app), a completed purchase could fail to disable ads, blank gaps where banner/native slots should have collapsed, and a `BannerAdView` Activity leak. Behavior changes: an account-hold subscription no longer disables ads, and premium users no longer reserve ad space in Compose
|
|
25
|
+
- **4.4.1** — Google Mobile Ads Next-Gen SDK 1.3.0 (from 1.2.1), plus repairs to API doc generation and the MCP documentation server
|
|
26
|
+
- **4.4.0** — Subscription offers can be **purchased individually** (`subscribe(activity, offer)`), offer lookup by id/base plan/tag, cross-cadence price normalization (`BillingPeriod`, `getSavingsPercent`), trial eligibility, Play Billing 9 one-time product offers, and client-side **account hold** detection. See [[Subscription Offers]]
|
|
27
|
+
- **4.3.x** — All standard banner sizes (`BannerAdSize`), custom native templates, and app-open ad freshness enforcement
|
|
28
|
+
- **4.2.0** — Migrated to the Google Mobile Ads **Next-Gen SDK** and Play Billing 9. `MobileAds.initialize()` must now be called explicitly before any ad request
|
|
29
|
+
|
|
30
|
+
> Upgrading from 3.x or earlier? Read the [Migrating to 4.2.0](https://github.com/i2hammad/AdManageKit#migrating-to-420) notes first — it is the one release in the 4.x line that is not source-compatible.
|
|
31
|
+
|
|
32
|
+
Full details: [Changelog](https://github.com/i2hammad/AdManageKit/blob/main/CHANGELOG.md) · [Release Notes](https://github.com/i2hammad/AdManageKit/tree/main/docs/release-notes)
|
|
16
33
|
|
|
17
34
|
## Features
|
|
18
35
|
|
|
@@ -23,14 +40,16 @@ AdManageKit is a comprehensive Android library designed to simplify the integrat
|
|
|
23
40
|
- **App Open Ads**: Lifecycle-aware with activity exclusion
|
|
24
41
|
|
|
25
42
|
### NativeTemplateView (v2.6.0+)
|
|
26
|
-
-
|
|
43
|
+
- 38 Template Styles: card_modern, material3, minimal, list_item, magazine, app_store, social_feed, spotlight, plus the video_* and flat_* families
|
|
27
44
|
- XML & Programmatic: Set templates via `app:adTemplate` or `setTemplate()`
|
|
45
|
+
- Custom Templates (v4.3.0+): supply your own layout via `setCustomTemplate()` or `app:customAdLayout`
|
|
28
46
|
- Material 3 Theming: Automatic dark/light mode support
|
|
29
47
|
|
|
30
48
|
### Ad Loading Strategies (v2.6.0+)
|
|
31
49
|
- **ON_DEMAND**: Fetch fresh ads with loading dialog
|
|
32
50
|
- **ONLY_CACHE**: Instant display from cache
|
|
33
51
|
- **HYBRID**: Cache-first with fallback fetch (recommended)
|
|
52
|
+
- **FRESH_WITH_CACHE_FALLBACK**: Fetch fresh, fall back to cache on failure
|
|
34
53
|
|
|
35
54
|
### Centralized Configuration
|
|
36
55
|
- **AdManageKitConfig**: Single configuration point
|
|
@@ -65,27 +84,39 @@ dependencyResolutionManagement {
|
|
|
65
84
|
**Step 2:** Add dependencies to your app's `build.gradle`:
|
|
66
85
|
|
|
67
86
|
```groovy
|
|
68
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:
|
|
69
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:
|
|
70
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:
|
|
87
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
88
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.3'
|
|
89
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
71
90
|
|
|
72
91
|
// For Jetpack Compose support
|
|
73
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:
|
|
92
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v4.4.3'
|
|
93
|
+
|
|
94
|
+
// For Yandex Ads multi-provider support
|
|
95
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:v4.4.3'
|
|
74
96
|
```
|
|
75
97
|
|
|
76
|
-
**Step 3:**
|
|
98
|
+
**Step 3:** Ensure your app's `compileSdk` is **37 or higher** (required transitively as of 4.2.0).
|
|
99
|
+
|
|
100
|
+
**Step 4:** Sync your project with Gradle.
|
|
77
101
|
|
|
78
102
|
### Quick Configuration
|
|
79
103
|
|
|
80
104
|
Configure AdManageKit in your Application class:
|
|
81
105
|
|
|
106
|
+
> **Since 4.2.0 you must call `MobileAds.initialize()` yourself.** The Next-Gen SDK removed the legacy SDK's silent lazy-init, so an app that skips it never loads ads. AdManageKit does not call it for you, because it does not own your consent flow.
|
|
107
|
+
|
|
82
108
|
```kotlin
|
|
83
109
|
class MyApp : Application() {
|
|
84
|
-
|
|
110
|
+
var appOpenManager: AppOpenManager? = null
|
|
85
111
|
|
|
86
112
|
override fun onCreate() {
|
|
87
113
|
super.onCreate()
|
|
88
114
|
|
|
115
|
+
initAds()
|
|
116
|
+
|
|
117
|
+
// Set up billing
|
|
118
|
+
BillingConfig.setPurchaseProvider(BillingPurchaseProvider())
|
|
119
|
+
|
|
89
120
|
// Configure AdManageKit
|
|
90
121
|
AdManageKitConfig.apply {
|
|
91
122
|
debugMode = BuildConfig.DEBUG
|
|
@@ -100,16 +131,29 @@ class MyApp : Application() {
|
|
|
100
131
|
// Auto-reload interstitial after showing
|
|
101
132
|
interstitialAutoReload = true // default: true
|
|
102
133
|
}
|
|
134
|
+
}
|
|
103
135
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//
|
|
108
|
-
|
|
136
|
+
private fun initAds() {
|
|
137
|
+
val config = InitializationConfig.Builder(readApplicationIdFromManifest()).build()
|
|
138
|
+
|
|
139
|
+
// initialize() blocks, so keep it off the main thread or it can ANR.
|
|
140
|
+
Thread {
|
|
141
|
+
MobileAds.initialize(this, config)
|
|
142
|
+
|
|
143
|
+
// Construct AppOpenManager only after initialize() returns. Constructing it
|
|
144
|
+
// arms its ProcessLifecycleOwner observer, and onStart() fires as soon as any
|
|
145
|
+
// activity starts — created earlier, that observer can race ahead of
|
|
146
|
+
// initialization and issue a load the Next-Gen SDK rejects as "not initialized".
|
|
147
|
+
Handler(Looper.getMainLooper()).post {
|
|
148
|
+
appOpenManager = AppOpenManager(this, "your-app-open-ad-unit-id")
|
|
149
|
+
}
|
|
150
|
+
}.start()
|
|
109
151
|
}
|
|
110
152
|
}
|
|
111
153
|
```
|
|
112
154
|
|
|
155
|
+
The Next-Gen SDK no longer reads the application id from the manifest automatically, so `readApplicationIdFromManifest()` pulls `com.google.android.gms.ads.APPLICATION_ID` from your `ApplicationInfo` metadata. See the sample app's [`MyApplication.kt`](https://github.com/i2hammad/AdManageKit/blob/main/app/src/main/java/com/i2hammad/admanagekit/sample/MyApplication.kt) for the full version.
|
|
156
|
+
|
|
113
157
|
## Wiki Pages
|
|
114
158
|
|
|
115
159
|
### Ad Types
|
|
@@ -128,6 +172,14 @@ class MyApp : Application() {
|
|
|
128
172
|
- [[Multi-Provider Waterfall]] - Load ads from multiple networks with automatic fallback
|
|
129
173
|
- [[Yandex Integration]] - Yandex Ads SDK provider setup and configuration
|
|
130
174
|
|
|
175
|
+
### Billing
|
|
176
|
+
- [[Billing Integration]] - Play Billing setup, products, and purchase flows
|
|
177
|
+
- [[Purchase Categories]] - Product type classification
|
|
178
|
+
- [[Consumable Products]] - Consumable in-app purchases
|
|
179
|
+
- [[Subscriptions]] - Subscription state, renewal, and account hold
|
|
180
|
+
- [[Subscription Offers]] - Multi-offer paywalls, price comparison, trial eligibility
|
|
181
|
+
- [[Subscription Upgrades]] - Plan changes and proration modes
|
|
182
|
+
|
|
131
183
|
## Sample Project
|
|
132
184
|
|
|
133
185
|
The `app` module demonstrates all features. To run:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Interstitial Ads - AdManageKit
|
|
1
|
+
# Interstitial Ads - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
5
|
AdManageKit provides a complete interstitial ad stack with `AdManager` and the fluent `InterstitialAdBuilder`. Features include loading strategies, automatic retry, frequency controls, splash screen support, and Jetpack Compose utilities.
|
|
6
6
|
|
|
7
|
-
**Library Version**:
|
|
7
|
+
**Library Version**: v4.4.3
|
|
8
8
|
|
|
9
9
|
## What's New
|
|
10
10
|
|
|
@@ -23,11 +23,11 @@ AdManageKit provides a complete interstitial ad stack with `AdManager` and the f
|
|
|
23
23
|
|
|
24
24
|
```groovy
|
|
25
25
|
dependencies {
|
|
26
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:
|
|
27
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:
|
|
28
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:
|
|
26
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
27
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
28
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.3'
|
|
29
29
|
// Optional - Jetpack Compose
|
|
30
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:
|
|
30
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v4.4.3'
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
@@ -58,6 +58,8 @@ class MyApp : Application() {
|
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
> **Since 4.2.0 you must also call `MobileAds.initialize()` yourself**, before any ad request — the Next-Gen SDK removed the legacy SDK's silent lazy-init. This snippet covers configuration only. See [[Home]] or the sample app's [`MyApplication.kt`](https://github.com/i2hammad/AdManageKit/blob/main/app/src/main/java/com/i2hammad/admanagekit/sample/MyApplication.kt) for the initialization pattern.
|
|
62
|
+
|
|
61
63
|
## Option 1: Direct AdManager
|
|
62
64
|
|
|
63
65
|
### Basic Usage
|
|
@@ -104,6 +106,7 @@ fun showInterstitial(activity: Activity) {
|
|
|
104
106
|
| ON_DEMAND | Always fetch fresh ad with dialog |
|
|
105
107
|
| ONLY_CACHE | Show cached if ready, skip otherwise |
|
|
106
108
|
| HYBRID | Show cached if ready, fetch fresh otherwise |
|
|
109
|
+
| FRESH_WITH_CACHE_FALLBACK | Fetch fresh, fall back to cache if the load fails |
|
|
107
110
|
|
|
108
111
|
```kotlin
|
|
109
112
|
// Set strategy
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
# Jetpack Compose Integration - AdManageKit
|
|
1
|
+
# Jetpack Compose Integration - AdManageKit v4.4.3
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
5
|
AdManageKit provides first-class Jetpack Compose support with composable functions for all ad types, state management helpers, and programmatic native ad loading.
|
|
6
6
|
|
|
7
|
-
**Library Version**:
|
|
7
|
+
**Library Version**: v4.4.3
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
11
|
```groovy
|
|
12
12
|
dependencies {
|
|
13
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:
|
|
14
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:
|
|
15
|
-
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:
|
|
13
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3'
|
|
14
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3'
|
|
15
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v4.4.3'
|
|
16
16
|
}
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -60,6 +60,27 @@ fun MyScreen() {
|
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Custom Templates & Shimmer (v4.3.0+)
|
|
64
|
+
|
|
65
|
+
If none of the 38 built-in templates fit, pass your own layout instead of a `template`:
|
|
66
|
+
|
|
67
|
+
```kotlin
|
|
68
|
+
NativeTemplateCompose(
|
|
69
|
+
adUnitId = "ca-app-pub-xxx/yyy",
|
|
70
|
+
customLayoutResId = R.layout.my_native_ad,
|
|
71
|
+
customShimmerResId = R.layout.my_native_ad_shimmer, // recommended, see below
|
|
72
|
+
customSizeHint = NativeAdSize.MEDIUM
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`customLayoutResId` takes precedence over `template`. The layout's root must be (or inflate as) a Next-Gen SDK `NativeAdView`, reusing the standard asset ids so the library can bind them: `ad_headline`, `ad_body`, `ad_call_to_action`, `ad_app_icon`, `ad_advertiser`, `ad_media`, `ad_stars`, `ad_choices_view`. Omitted ids are simply not populated, but keep the call-to-action fully visible and tappable — the native ad validator flags clipping as a policy violation.
|
|
77
|
+
|
|
78
|
+
> **`customShimmerResId` is optional, but omitting it is rarely what you want.** The shimmer then falls back to the one belonging to `template` (default `CARD_MODERN`), so a custom layout still shows a placeholder — just one shaped like a different ad, which visibly jumps when the real ad arrives. Either supply a matching shimmer, or set `template` to whichever built-in most resembles your layout so the fallback is the right shape. Passing `0` is the same as omitting it.
|
|
79
|
+
|
|
80
|
+
`customSizeHint` classifies the ad for the cache and gives the Yandex waterfall a fallback size, since a custom layout has no built-in size bucket — `SMALL` (icon + title + CTA), `MEDIUM` (adds body), `LARGE` (adds media). It does not affect how your layout is measured.
|
|
81
|
+
|
|
82
|
+
The XML and programmatic equivalents are covered in [[Native Ads|NativeAdManager]].
|
|
83
|
+
|
|
63
84
|
### Traditional Native Composables
|
|
64
85
|
|
|
65
86
|
```kotlin
|
|
@@ -38,11 +38,11 @@ This is fully backward compatible -- if no provider chains are configured, all e
|
|
|
38
38
|
|
|
39
39
|
```groovy
|
|
40
40
|
dependencies {
|
|
41
|
-
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit:
|
|
42
|
-
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-core:
|
|
41
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit:v4.4.3"
|
|
42
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.3"
|
|
43
43
|
|
|
44
44
|
// Add Yandex provider
|
|
45
|
-
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:
|
|
45
|
+
implementation "com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:v4.4.3"
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -161,7 +161,7 @@ if (isRussia) {
|
|
|
161
161
|
All existing features continue to work when the waterfall is active:
|
|
162
162
|
|
|
163
163
|
- Time-based and count-based interstitial display
|
|
164
|
-
- Loading strategies (ON_DEMAND, ONLY_CACHE, HYBRID)
|
|
164
|
+
- Loading strategies (ON_DEMAND, ONLY_CACHE, HYBRID, FRESH_WITH_CACHE_FALLBACK)
|
|
165
165
|
- Shimmer loading placeholders
|
|
166
166
|
- Loading dialogs for interstitials
|
|
167
167
|
- Welcome back dialog for app open ads
|