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,479 @@
|
|
|
1
|
+
# Release Notes - v2.9.0
|
|
2
|
+
|
|
3
|
+
## Highlights
|
|
4
|
+
|
|
5
|
+
- **6 New Native Ad Templates**: APP_STORE, SOCIAL_FEED, GRADIENT_CARD, PILL_BANNER, SPOTLIGHT, MEDIA_CONTENT_SPLIT
|
|
6
|
+
- **AdChoices Placement Control**: Configure AdChoices position in NativeTemplateView
|
|
7
|
+
- **Enhanced Purchase Tracking**: Comprehensive purchase categorization system (Consumable, Lifetime, Remove Ads, Subscription)
|
|
8
|
+
- **Purchase History Listener**: Track purchases and consumption events for your own persistence
|
|
9
|
+
- **Subscription Lifecycle Management**: Active, Cancelled, Expired state detection with upgrade/downgrade support
|
|
10
|
+
- **Improved PurchaseResult**: Full data capture including signature, originalJson, account identifiers
|
|
11
|
+
- **No Auto-Consume**: Developers have full control over when to consume purchases
|
|
12
|
+
- **Dependency Updates**: Google Play Billing 8.1.0, AdMob 24.8.0, Firebase 34.6.0, Lifecycle 2.10.0
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## New Features
|
|
17
|
+
|
|
18
|
+
### Native Ad Templates
|
|
19
|
+
|
|
20
|
+
#### 6 New Templates
|
|
21
|
+
|
|
22
|
+
| Template | Description | Best For |
|
|
23
|
+
|----------|-------------|----------|
|
|
24
|
+
| `APP_STORE` | App listing style with large icon and download button | App promotion |
|
|
25
|
+
| `SOCIAL_FEED` | Social media post style | Feed integration |
|
|
26
|
+
| `GRADIENT_CARD` | Modern card with gradient background | Premium feel |
|
|
27
|
+
| `PILL_BANNER` | Compact pill-shaped banner | Inline placement |
|
|
28
|
+
| `SPOTLIGHT` | Hero/spotlight style with emphasis | High visibility |
|
|
29
|
+
| `MEDIA_CONTENT_SPLIT` | Split layout with media and content | Balanced display |
|
|
30
|
+
|
|
31
|
+
```kotlin
|
|
32
|
+
// Use new templates in XML
|
|
33
|
+
<com.i2hammad.admanagekit.admob.NativeTemplateView
|
|
34
|
+
android:layout_width="match_parent"
|
|
35
|
+
android:layout_height="wrap_content"
|
|
36
|
+
app:adTemplate="app_store" />
|
|
37
|
+
|
|
38
|
+
// Or programmatically
|
|
39
|
+
nativeTemplateView.setTemplate(NativeAdTemplate.SOCIAL_FEED)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### AdChoices Placement Control
|
|
43
|
+
|
|
44
|
+
Configure AdChoices icon position:
|
|
45
|
+
|
|
46
|
+
```kotlin
|
|
47
|
+
// Programmatic control
|
|
48
|
+
nativeTemplateView.setAdChoicesPlacement(
|
|
49
|
+
NativeAdOptions.ADCHOICES_TOP_LEFT,
|
|
50
|
+
useSDKPlacement = true // Use SDK auto-placement instead of XML position
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
// Or use template's XML-defined position (default)
|
|
54
|
+
nativeTemplateView.setUseCustomAdChoicesView(true)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**XML attribute:**
|
|
58
|
+
```xml
|
|
59
|
+
<com.i2hammad.admanagekit.admob.NativeTemplateView
|
|
60
|
+
app:adChoicesPlacement="top_left" />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Options: `top_left`, `top_right` (default), `bottom_left`, `bottom_right`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### Billing Module
|
|
68
|
+
|
|
69
|
+
### 1. Purchase Categories
|
|
70
|
+
|
|
71
|
+
Products can now be categorized for better tracking and ad-disabling logic:
|
|
72
|
+
|
|
73
|
+
```kotlin
|
|
74
|
+
enum class PurchaseCategory {
|
|
75
|
+
CONSUMABLE, // Coins, gems (can buy multiple times)
|
|
76
|
+
FEATURE_UNLOCK, // Unlock level pack (one-time, doesn't disable ads)
|
|
77
|
+
LIFETIME_PREMIUM, // Permanent premium (disables ads)
|
|
78
|
+
REMOVE_ADS // Remove ads only (disables ads)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Usage
|
|
82
|
+
val items = listOf(
|
|
83
|
+
PurchaseItem("coins_100", TYPE_IAP.PURCHASE, PurchaseCategory.CONSUMABLE),
|
|
84
|
+
PurchaseItem("remove_ads", TYPE_IAP.PURCHASE, PurchaseCategory.REMOVE_ADS),
|
|
85
|
+
PurchaseItem("lifetime_premium", TYPE_IAP.PURCHASE, PurchaseCategory.LIFETIME_PREMIUM),
|
|
86
|
+
PurchaseItem("premium_monthly", "free_trial", TYPE_IAP.SUBSCRIPTION)
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 2. Purchase History Listener
|
|
91
|
+
|
|
92
|
+
Track all purchase events for your own persistence/analytics:
|
|
93
|
+
|
|
94
|
+
```kotlin
|
|
95
|
+
AppPurchase.getInstance().setPurchaseHistoryListener(object : PurchaseHistoryListener {
|
|
96
|
+
override fun onNewPurchase(productId: String, purchase: PurchaseResult) {
|
|
97
|
+
// Purchase acknowledged - save to your database
|
|
98
|
+
// Includes: orderId, quantity, purchaseTime, originalJson, signature
|
|
99
|
+
savePurchase(productId, purchase)
|
|
100
|
+
|
|
101
|
+
// For consumables: grant items then consume
|
|
102
|
+
if (productId == "coins_100") {
|
|
103
|
+
userBalance += 100 * purchase.quantity
|
|
104
|
+
AppPurchase.getInstance().consumePurchase(productId)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
override fun onPurchaseConsumed(productId: String, purchase: PurchaseResult) {
|
|
109
|
+
// Mark as consumed in your tracking system
|
|
110
|
+
markConsumed(productId, purchase.orderId)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 3. Subscription State Management
|
|
116
|
+
|
|
117
|
+
Detect subscription lifecycle states:
|
|
118
|
+
|
|
119
|
+
```kotlin
|
|
120
|
+
// Check subscription state
|
|
121
|
+
val state = AppPurchase.getInstance().getSubscriptionState("premium_monthly")
|
|
122
|
+
when (state) {
|
|
123
|
+
SubscriptionState.ACTIVE -> showPremiumUI()
|
|
124
|
+
SubscriptionState.CANCELLED -> showCancelledWarning() // Still has access
|
|
125
|
+
SubscriptionState.EXPIRED -> showSubscribeButton()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Helper methods
|
|
129
|
+
AppPurchase.getInstance().isSubscribed() // Any active subscription
|
|
130
|
+
AppPurchase.getInstance().hasSubscriptionCancelled() // User cancelled
|
|
131
|
+
AppPurchase.getInstance().willSubscriptionsRenew() // All will renew
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 4. Subscription Upgrade/Downgrade
|
|
135
|
+
|
|
136
|
+
Full support for subscription changes with proration modes:
|
|
137
|
+
|
|
138
|
+
```kotlin
|
|
139
|
+
// Simple upgrade (charges price difference immediately)
|
|
140
|
+
AppPurchase.getInstance().upgradeSubscription(activity, "premium_yearly")
|
|
141
|
+
|
|
142
|
+
// Simple downgrade (takes effect at next renewal)
|
|
143
|
+
AppPurchase.getInstance().downgradeSubscription(activity, "premium_basic")
|
|
144
|
+
|
|
145
|
+
// Full control with custom proration
|
|
146
|
+
AppPurchase.getInstance().changeSubscription(
|
|
147
|
+
activity,
|
|
148
|
+
"premium_monthly", // Current subscription
|
|
149
|
+
"premium_yearly", // New subscription
|
|
150
|
+
SubscriptionReplacementMode.CHARGE_PRORATED_PRICE
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Replacement Modes:**
|
|
155
|
+
|
|
156
|
+
| Mode | Use Case | Effect |
|
|
157
|
+
|------|----------|--------|
|
|
158
|
+
| `CHARGE_PRORATED_PRICE` | Upgrades | User pays price difference now |
|
|
159
|
+
| `DEFERRED` | Downgrades | Change at next renewal |
|
|
160
|
+
| `WITH_TIME_PRORATION` | Either | Immediate, remaining value credited |
|
|
161
|
+
| `CHARGE_FULL_PRICE` | Either | Immediate, full price charged |
|
|
162
|
+
| `WITHOUT_PRORATION` | Either | Immediate, no price adjustment |
|
|
163
|
+
|
|
164
|
+
### 5. Enhanced PurchaseResult
|
|
165
|
+
|
|
166
|
+
Comprehensive purchase data from Billing Library v8:
|
|
167
|
+
|
|
168
|
+
```kotlin
|
|
169
|
+
val result = PurchaseResult.fromPurchase(purchase)
|
|
170
|
+
|
|
171
|
+
// New fields
|
|
172
|
+
result.originalJson // For server-side verification
|
|
173
|
+
result.signature // For signature verification
|
|
174
|
+
result.obfuscatedAccountId // Account identifier
|
|
175
|
+
result.obfuscatedProfileId // Profile identifier
|
|
176
|
+
result.productType // "inapp" or "subs"
|
|
177
|
+
result.isConsumed // Consumption tracking
|
|
178
|
+
result.consumedTime // When consumed
|
|
179
|
+
|
|
180
|
+
// Helper methods
|
|
181
|
+
result.isPurchased() // PURCHASED state
|
|
182
|
+
result.isPending() // PENDING state
|
|
183
|
+
result.getFirstProductId() // Primary product ID
|
|
184
|
+
result.getPurchaseTimeFormatted() // "2024-01-15 14:30:00"
|
|
185
|
+
result.hasVerificationData() // Has json + signature
|
|
186
|
+
result.isSubscriptionActive() // Has access (active or cancelled)
|
|
187
|
+
result.willSubscriptionRenew() // Will auto-renew
|
|
188
|
+
result.getSubscriptionStateString() // "Active", "Cancelled", etc.
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 6. Smart `isPurchased()` Logic
|
|
192
|
+
|
|
193
|
+
Only ad-disabling purchases affect `isPurchased()`:
|
|
194
|
+
|
|
195
|
+
```kotlin
|
|
196
|
+
// Returns true for:
|
|
197
|
+
// - Active subscriptions
|
|
198
|
+
// - LIFETIME_PREMIUM purchases
|
|
199
|
+
// - REMOVE_ADS purchases
|
|
200
|
+
|
|
201
|
+
// Returns false for:
|
|
202
|
+
// - Consumable purchases (coins, gems)
|
|
203
|
+
// - Feature unlocks (unless configured to disable ads)
|
|
204
|
+
// - No purchases
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## API Changes
|
|
210
|
+
|
|
211
|
+
### NativeAdTemplate - New Templates
|
|
212
|
+
|
|
213
|
+
| Template | Layout | Shimmer |
|
|
214
|
+
|----------|--------|---------|
|
|
215
|
+
| `APP_STORE` | `layout_native_app_store` | `layout_shimmer_app_store` |
|
|
216
|
+
| `SOCIAL_FEED` | `layout_native_social_feed` | `layout_shimmer_social_feed` |
|
|
217
|
+
| `GRADIENT_CARD` | `layout_native_gradient_card` | `layout_shimmer_gradient_card` |
|
|
218
|
+
| `PILL_BANNER` | `layout_native_pill_banner` | `layout_shimmer_pill_banner` |
|
|
219
|
+
| `SPOTLIGHT` | `layout_native_spotlight` | `layout_shimmer_spotlight` |
|
|
220
|
+
| `MEDIA_CONTENT_SPLIT` | `layout_native_media_content_split` | `layout_shimmer_media_content_split` |
|
|
221
|
+
|
|
222
|
+
### NativeTemplateView - New Methods
|
|
223
|
+
|
|
224
|
+
| Method | Description |
|
|
225
|
+
|--------|-------------|
|
|
226
|
+
| `setAdChoicesPlacement(placement, useSDKPlacement)` | Set AdChoices icon position |
|
|
227
|
+
| `getAdChoicesPlacement()` | Get current AdChoices placement |
|
|
228
|
+
| `setUseCustomAdChoicesView(useCustomView)` | Toggle between template XML and SDK positioning |
|
|
229
|
+
|
|
230
|
+
### NativeTemplateView - New XML Attributes
|
|
231
|
+
|
|
232
|
+
| Attribute | Values | Default |
|
|
233
|
+
|-----------|--------|---------|
|
|
234
|
+
| `app:adChoicesPlacement` | `top_left`, `top_right`, `bottom_left`, `bottom_right` | `top_right` |
|
|
235
|
+
|
|
236
|
+
### AppPurchase - New Methods
|
|
237
|
+
|
|
238
|
+
| Method | Description |
|
|
239
|
+
|--------|-------------|
|
|
240
|
+
| `setPurchaseHistoryListener()` | Set listener for purchase events |
|
|
241
|
+
| `consumePurchase(productId)` | Manually consume a purchased product |
|
|
242
|
+
| `refreshPurchases()` | Refresh purchase state from Google |
|
|
243
|
+
| `isSubscribed(subscriptionId)` | Check specific subscription |
|
|
244
|
+
| `getSubscriptionState(subscriptionId)` | Get subscription lifecycle state |
|
|
245
|
+
| `getActiveSubscriptions()` | Get all active subscriptions |
|
|
246
|
+
| `hasSubscriptionCancelled()` | Check if any subscription cancelled |
|
|
247
|
+
| `willSubscriptionsRenew()` | Check if all subscriptions will renew |
|
|
248
|
+
| `getSubscription(subscriptionId)` | Get subscription PurchaseResult |
|
|
249
|
+
| `hasLifetimePurchase()` | Check for lifetime purchases |
|
|
250
|
+
| `hasLifetimePremium()` | Check for LIFETIME_PREMIUM category |
|
|
251
|
+
| `hasRemoveAdsPurchase()` | Check for REMOVE_ADS category |
|
|
252
|
+
| `getActivePurchaseType()` | Get type disabling ads |
|
|
253
|
+
| `getPurchaseCategory(productId)` | Get product's category |
|
|
254
|
+
| `isProductOwned(productId)` | Check if product is owned |
|
|
255
|
+
| `upgradeSubscription()` | Simple upgrade with default proration |
|
|
256
|
+
| `downgradeSubscription()` | Simple downgrade with deferred mode |
|
|
257
|
+
| `changeSubscription()` | Full upgrade/downgrade control |
|
|
258
|
+
| `updateSubscription()` | Low-level subscription update |
|
|
259
|
+
|
|
260
|
+
### AppPurchase - Deprecated Methods
|
|
261
|
+
|
|
262
|
+
| Method | Replacement |
|
|
263
|
+
|--------|-------------|
|
|
264
|
+
| `setConsumePurchase(boolean)` | Use `PurchaseItem.isConsumable` per-product |
|
|
265
|
+
|
|
266
|
+
### PurchaseItem - New Properties
|
|
267
|
+
|
|
268
|
+
| Property | Description |
|
|
269
|
+
|----------|-------------|
|
|
270
|
+
| `category` | PurchaseCategory enum |
|
|
271
|
+
| `isConsumable` | Whether product is consumable |
|
|
272
|
+
|
|
273
|
+
### PurchaseItem - New Methods
|
|
274
|
+
|
|
275
|
+
| Method | Description |
|
|
276
|
+
|--------|-------------|
|
|
277
|
+
| `shouldDisableAds()` | Check if purchase should disable ads |
|
|
278
|
+
| `isLifetimePurchase()` | Check if lifetime (not subscription) |
|
|
279
|
+
|
|
280
|
+
### PurchaseResult - New Fields
|
|
281
|
+
|
|
282
|
+
| Field | Description |
|
|
283
|
+
|-------|-------------|
|
|
284
|
+
| `originalJson` | Raw JSON for server verification |
|
|
285
|
+
| `signature` | Purchase signature |
|
|
286
|
+
| `obfuscatedAccountId` | Account identifier |
|
|
287
|
+
| `obfuscatedProfileId` | Profile identifier |
|
|
288
|
+
| `productType` | "inapp" or "subs" |
|
|
289
|
+
| `isConsumed` | Consumption status |
|
|
290
|
+
| `consumedTime` | Time of consumption |
|
|
291
|
+
|
|
292
|
+
### PurchaseResult - New Methods
|
|
293
|
+
|
|
294
|
+
| Method | Description |
|
|
295
|
+
|--------|-------------|
|
|
296
|
+
| `fromPurchase(Purchase)` | Factory method from Google Purchase |
|
|
297
|
+
| `isPurchased()` | Check if PURCHASED state |
|
|
298
|
+
| `isPending()` | Check if PENDING state |
|
|
299
|
+
| `getFirstProductId()` | Get primary product ID |
|
|
300
|
+
| `containsProduct(productId)` | Check if contains product |
|
|
301
|
+
| `getPurchaseTimeFormatted()` | Get formatted date string |
|
|
302
|
+
| `getPurchaseDate()` | Get Date object |
|
|
303
|
+
| `markAsConsumed()` | Mark as consumed |
|
|
304
|
+
| `hasVerificationData()` | Check for json + signature |
|
|
305
|
+
| `isSubscription()` | Check if subscription type |
|
|
306
|
+
| `isInApp()` | Check if in-app type |
|
|
307
|
+
| `getSubscriptionState()` | Get SubscriptionState enum |
|
|
308
|
+
| `isSubscriptionActive()` | Check if has access |
|
|
309
|
+
| `willSubscriptionRenew()` | Check if will renew |
|
|
310
|
+
| `isSubscriptionCancelled()` | Check if cancelled |
|
|
311
|
+
| `getSubscriptionStateString()` | Get human-readable state |
|
|
312
|
+
|
|
313
|
+
### New Enums
|
|
314
|
+
|
|
315
|
+
```kotlin
|
|
316
|
+
// Purchase type for ad-disabling detection
|
|
317
|
+
enum class PurchaseType {
|
|
318
|
+
NONE, SUBSCRIPTION, LIFETIME_PREMIUM, REMOVE_ADS, LIFETIME, CONSUMABLE, UNKNOWN
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Subscription lifecycle states
|
|
322
|
+
enum class SubscriptionState {
|
|
323
|
+
ACTIVE, CANCELLED, GRACE_PERIOD, ON_HOLD, PAUSED, EXPIRED, NOT_SUBSCRIPTION
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Subscription upgrade/downgrade modes
|
|
327
|
+
enum class SubscriptionReplacementMode {
|
|
328
|
+
WITH_TIME_PRORATION, CHARGE_PRORATED_PRICE, CHARGE_FULL_PRICE, DEFERRED, WITHOUT_PRORATION
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Breaking Changes
|
|
335
|
+
|
|
336
|
+
### No Auto-Consume
|
|
337
|
+
|
|
338
|
+
Products are **no longer auto-consumed**. You must call `consumePurchase(productId)` manually after granting items to the user:
|
|
339
|
+
|
|
340
|
+
```kotlin
|
|
341
|
+
// Before v2.9.0: Products could be auto-consumed
|
|
342
|
+
AppPurchase.getInstance().setConsumePurchase(true) // Deprecated
|
|
343
|
+
|
|
344
|
+
// After v2.9.0: Manual consumption required
|
|
345
|
+
AppPurchase.getInstance().setPurchaseHistoryListener(object : PurchaseHistoryListener {
|
|
346
|
+
override fun onNewPurchase(productId: String, purchase: PurchaseResult) {
|
|
347
|
+
grantItems(productId, purchase.quantity)
|
|
348
|
+
AppPurchase.getInstance().consumePurchase(productId) // Manual!
|
|
349
|
+
}
|
|
350
|
+
override fun onPurchaseConsumed(productId: String, purchase: PurchaseResult) {}
|
|
351
|
+
})
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Default Category Change
|
|
355
|
+
|
|
356
|
+
`PurchaseItem` default category changed from `FEATURE_UNLOCK` to `LIFETIME_PREMIUM`:
|
|
357
|
+
|
|
358
|
+
```kotlin
|
|
359
|
+
// If you were relying on default category, explicitly set it
|
|
360
|
+
PurchaseItem("product_id", TYPE_IAP.PURCHASE, PurchaseCategory.FEATURE_UNLOCK)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Migration Guide
|
|
366
|
+
|
|
367
|
+
### From 2.8.0 to 2.9.0
|
|
368
|
+
|
|
369
|
+
#### 1. Update Consumable Product Handling
|
|
370
|
+
|
|
371
|
+
```kotlin
|
|
372
|
+
// Old approach (auto-consume)
|
|
373
|
+
AppPurchase.getInstance().setConsumePurchase(true)
|
|
374
|
+
|
|
375
|
+
// New approach (manual consume)
|
|
376
|
+
AppPurchase.getInstance().setPurchaseHistoryListener(object : PurchaseHistoryListener {
|
|
377
|
+
override fun onNewPurchase(productId: String, purchase: PurchaseResult) {
|
|
378
|
+
when (productId) {
|
|
379
|
+
"coins_100" -> {
|
|
380
|
+
addCoins(100 * purchase.quantity)
|
|
381
|
+
AppPurchase.getInstance().consumePurchase(productId)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
override fun onPurchaseConsumed(productId: String, purchase: PurchaseResult) {
|
|
386
|
+
Log.d("Billing", "Consumed: $productId")
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### 2. Use Purchase Categories
|
|
392
|
+
|
|
393
|
+
```kotlin
|
|
394
|
+
// Old approach
|
|
395
|
+
val items = listOf(
|
|
396
|
+
PurchaseItem("coins_100", TYPE_IAP.PURCHASE, true), // isConsumable
|
|
397
|
+
PurchaseItem("remove_ads", TYPE_IAP.PURCHASE)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
// New approach (explicit categories)
|
|
401
|
+
val items = listOf(
|
|
402
|
+
PurchaseItem("coins_100", TYPE_IAP.PURCHASE, PurchaseCategory.CONSUMABLE),
|
|
403
|
+
PurchaseItem("remove_ads", TYPE_IAP.PURCHASE, PurchaseCategory.REMOVE_ADS),
|
|
404
|
+
PurchaseItem("lifetime", TYPE_IAP.PURCHASE, PurchaseCategory.LIFETIME_PREMIUM)
|
|
405
|
+
)
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
#### 3. Check Purchase Type for UI
|
|
409
|
+
|
|
410
|
+
```kotlin
|
|
411
|
+
// Show appropriate UI based on purchase type
|
|
412
|
+
when (AppPurchase.getInstance().getActivePurchaseType()) {
|
|
413
|
+
PurchaseType.SUBSCRIPTION -> showSubscriberBadge()
|
|
414
|
+
PurchaseType.LIFETIME_PREMIUM -> showLifetimeBadge()
|
|
415
|
+
PurchaseType.REMOVE_ADS -> hideAds()
|
|
416
|
+
PurchaseType.NONE -> showPurchaseOptions()
|
|
417
|
+
else -> {}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Installation
|
|
424
|
+
|
|
425
|
+
```groovy
|
|
426
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v2.9.0'
|
|
427
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v2.9.0'
|
|
428
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v2.9.0'
|
|
429
|
+
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v2.9.0'
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Full Changelog
|
|
435
|
+
|
|
436
|
+
### Native Ad Module
|
|
437
|
+
|
|
438
|
+
- Added 6 new native ad templates: APP_STORE, SOCIAL_FEED, GRADIENT_CARD, PILL_BANNER, SPOTLIGHT, MEDIA_CONTENT_SPLIT
|
|
439
|
+
- Added shimmer loading layouts for all new templates
|
|
440
|
+
- Added AdChoices placement control in NativeTemplateView (`setAdChoicesPlacement()`)
|
|
441
|
+
- Added `adChoicesPlacement` XML attribute for declarative configuration
|
|
442
|
+
- Added `setUseCustomAdChoicesView()` for SDK vs template positioning control
|
|
443
|
+
- Added coroutine support in NativeTemplateView for async operations
|
|
444
|
+
- Updated screen type classification for new templates in NativeAdIntegrationManager
|
|
445
|
+
- Improved layout consistency across all native templates
|
|
446
|
+
|
|
447
|
+
### Billing Module Enhancements
|
|
448
|
+
|
|
449
|
+
- Added `PurchaseCategory` enum for product classification (CONSUMABLE, FEATURE_UNLOCK, LIFETIME_PREMIUM, REMOVE_ADS)
|
|
450
|
+
- Added `PurchaseHistoryListener` interface for tracking purchases and consumption
|
|
451
|
+
- Added `PurchaseResult.fromPurchase()` factory method with full data capture
|
|
452
|
+
- Added subscription state tracking (ACTIVE, CANCELLED, EXPIRED)
|
|
453
|
+
- Added subscription upgrade/downgrade with `SubscriptionReplacementMode`
|
|
454
|
+
- Added `refreshPurchases()` for manual purchase state refresh
|
|
455
|
+
- Enhanced `isPurchased()` to only consider ad-disabling purchases
|
|
456
|
+
- Enhanced `PurchaseResult` with originalJson, signature, account identifiers, consumption tracking
|
|
457
|
+
- Added helper methods: `hasLifetimePremium()`, `hasRemoveAdsPurchase()`, `getActivePurchaseType()`
|
|
458
|
+
- Added subscription methods: `getSubscriptionState()`, `hasSubscriptionCancelled()`, `willSubscriptionsRenew()`
|
|
459
|
+
- Removed auto-consume behavior - developers must call `consumePurchase()` manually
|
|
460
|
+
- Deprecated `setConsumePurchase()` in favor of per-product `isConsumable` flag
|
|
461
|
+
|
|
462
|
+
### Dependency Updates
|
|
463
|
+
|
|
464
|
+
| Dependency | Old Version | New Version |
|
|
465
|
+
|------------|-------------|-------------|
|
|
466
|
+
| Google Play Billing | 8.0.0 | 8.1.0 |
|
|
467
|
+
| Google Mobile Ads | 24.7.0 | 24.8.0 |
|
|
468
|
+
| Firebase BOM | 34.5.0 | 34.6.0 |
|
|
469
|
+
| Lifecycle (Process, ViewModel, Runtime) | 2.9.4 | 2.10.0 |
|
|
470
|
+
| Activity / Activity Compose | 1.11.0 | 1.12.0 |
|
|
471
|
+
| Compose BOM | 2025.10.01 | 2025.11.01 |
|
|
472
|
+
|
|
473
|
+
### Bug Fixes
|
|
474
|
+
|
|
475
|
+
- Fixed double callback issue in splash interstitial loading with timeout
|
|
476
|
+
- Fixed ad loading timeout now saves ad for next use instead of discarding
|
|
477
|
+
- Improved screen type detection for new native templates
|
|
478
|
+
- Fixed `IllegalArgumentException: View not attached to window manager` crash when dismissing dialogs after activity is destroyed (AppOpenManager, AdManager)
|
|
479
|
+
- Fixed welcome back dialog crash on activities without Material theme by wrapping context with `ContextThemeWrapper`
|