Skip to content

i2hammad/AdManageKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

119 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AdManageKit

JitPack API License

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.

Latest Version 3.4.4 fixes native ad show rate issues across all native views and adds null safety to RewardedAdManager.


Next-Gen GMA SDK Version

Beta Notice: The Next-Gen GMA SDK (com.google.android.libraries.ads.mobile.sdk) is currently in beta by Google, and AdManageKit's nextgen branch is also in beta. The underlying Google SDK may receive breaking changes until it reaches stable release. For production use, the main branch is the stable option.

AdManageKit offers a Next-Gen GMA SDK version on the nextgen branch, featuring Google's modern preloader-based ad loading system.

Why Next-Gen?

Feature Main Branch (GMS SDK) Next-Gen Branch
SDK play-services-ads (stable) ads-mobile-sdk (beta)
Ad Loading Traditional load/show Preloader-based with auto-refill
Threading Manual main thread dispatch Automatic background thread safety
Buffer System N/A Configurable ad buffers per type
Background Handling Basic Smart pending ad queue

Next-Gen Features

  • Preloader System: SDK automatically loads next ad after one is consumed
  • Background-Aware Ads: App open ads won't show when app is in background
  • Pending Ad Queue: Ads that load while backgrounded are saved for return
  • Configurable Buffers: Set how many ads to keep ready per type
// Next-Gen preloader configuration
AdManageKitConfig.apply {
    enableInterstitialPreloader = true
    enableAppOpenPreloader = true
    interstitialPreloaderBufferSize = 2
}

Migration Compatibility

Both branches use the same callback signatures via type aliases:

  • AdKitError → resolves to appropriate SDK error type
  • AdKitLoadError → resolves to appropriate SDK load error type
  • AdKitValue → resolves to appropriate SDK value type

Your callback implementations work on both branches without changes.

Which Version Should I Use?

Use Case Recommended
Production apps (stable) Main branch (v3.4.4)
New projects wanting latest features Nextgen branch (v4.1.1)
Testing preloader system Nextgen branch
Risk-averse production Main branch

What's New in 3.4.4

Native Ad Show Rate Fix

Fixed low show rates across all native ad views (NativeBannerSmall, NativeBannerMedium, NativeLarge, NativeTemplateView). Parent container visibility was not restored after a previous load failure, causing ads to load but remain invisible.

NativeBannerMedium Impression Fix

setNativeAd() was deferred via post {} which risked never executing. Changed to synchronous call for reliable impression registration. Also fixed shimmer overlay on cached/waterfall ads.

RewardedAdManager Null Safety

RewardedAdManager no longer crashes when methods are called before initialize(). All 5 public entry points now validate the ad unit ID and return appropriate callbacks.

For previous versions, see the Changelog or individual release notes.

Screenshots

NativeBannerSmall Ad Interstitial Ad App Open Ad UMP Consent Form
NativeBannerSmall ad displayed in app Interstitial ad with loading dialog App open ad on app launch UMP consent form

Demo Video

Watch a short demo of AdManageKit in action:

Watch on YouTube

Getting Started

Installation

Step 1: Add JitPack to your root build.gradle:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

Step 2: Add dependencies to your app's build.gradle:

Main Branch (Stable GMS SDK) Next-Gen Branch (Beta GMA SDK)
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit:v3.4.4'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v3.4.4'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v3.4.4'

// For Jetpack Compose support
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose:v3.4.4'

// For Yandex Ads multi-provider support
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:v3.4.4'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-nextgen:v4.1.1'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing-nextgen:v4.1.1'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core-nextgen:v4.1.1'

// For Jetpack Compose support
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-compose-nextgen:v4.1.1'

Step 3: Sync your project with Gradle.

Features

NativeTemplateView (v2.6.0+)

  • 27 Template Styles: card_modern, material3, app_store, social_feed, gradient_card, pill_banner, medium_horizontal, flexible, icon_left, top_icon_media, spotlight, and more
  • XML & Programmatic: Set templates via app:adTemplate or setTemplate()
  • Material 3 Theming: Automatic dark/light mode support
  • AdChoices Control: Configure placement position (v2.9.0+)
  • Video-Ready: All templates support video ads (120dp+ MediaView)
  • View Documentation

Ad Loading Strategies (v2.6.0+)

  • ON_DEMAND: Fetch fresh ads with loading dialog
  • ONLY_CACHE: Instant display from cache
  • HYBRID: Cache-first with fallback fetch (recommended)
  • View Documentation

Jetpack Compose Integration

  • BannerAdCompose, NativeAdCompose, InterstitialAdCompose
  • Programmatic native ads without predefined layouts
  • ConditionalAd, CacheWarmingEffect utilities

AdMob Ads Management

  • Banner Ads: Auto-refresh, collapsible banners, smart retry
  • Native Ads: Small, Medium, Large formats with caching
  • Interstitial Ads: Time/count-based triggers, dialog support
  • App Open Ads: Lifecycle-aware with activity exclusion

Centralized Configuration

  • AdManageKitConfig: Single configuration point
  • Environment-specific settings (debug vs production)
  • Runtime configuration changes

Intelligent Native Ad Caching

  • Screen-aware caching prevents collisions
  • Smart preloading with usage patterns
  • LRU cache with configurable expiration

Reliability & Performance

  • Smart retry with exponential backoff
  • Circuit breaker for failing ad units
  • Memory leak prevention with WeakReference

Privacy & Compliance

  • UMP consent management (GDPR/CCPA)
  • Automatic ad hiding for purchased users

Multi-Provider Waterfall (New)

  • Multiple Ad Networks: Load ads from AdMob, Yandex, and more with automatic fallback
  • Zero Code Changes: Configure provider chains once; all existing API calls use waterfall automatically
  • Per-Ad-Type Chains: Configure different provider orders for each ad format
  • Region-Based: Prioritize providers by user locale (e.g., Yandex first for Russia)
  • View Waterfall Documentation
  • Yandex Integration Guide

Multi-Module Architecture

  • Core Module: Shared interfaces and configuration
  • Compose Module: Jetpack Compose integration
  • Billing Module: Google Play Billing Library v8
  • Yandex Module: Yandex Ads SDK provider

Usage Guide

Quick Configuration

Configure AdManageKit in your Application class:

class MyApp : Application() {
    private lateinit var appOpenManager: AppOpenManager

    override fun onCreate() {
        super.onCreate()

        // Configure AdManageKit
        AdManageKitConfig.apply {
            debugMode = BuildConfig.DEBUG
            enableSmartPreloading = true
            autoRetryFailedAds = true

            // Ad Loading Strategies (v2.6.0+)
            interstitialLoadingStrategy = AdLoadingStrategy.HYBRID
            appOpenLoadingStrategy = AdLoadingStrategy.HYBRID
            nativeLoadingStrategy = AdLoadingStrategy.HYBRID

            // Auto-reload ads after showing (v2.7.0+)
            interstitialAutoReload = true  // default: true
            appOpenAutoReload = true       // default: true
            rewardedAutoReload = true      // default: true
        }

        // Set up billing
        BillingConfig.setPurchaseProvider(BillingPurchaseProvider())

        // Initialize app open ads
        appOpenManager = AppOpenManager(this, "your-app-open-ad-unit-id")
    }
}

Multi-Provider Waterfall (Optional)

Add Yandex (or other providers) as fallback ad networks with zero changes to your existing ad loading code:

// Add Yandex module
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-yandex:v3.4.4'
// In Application.onCreate(), after AdManageKitConfig setup:
YandexProviderRegistration.initialize(this)
val admob = AdMobProviderRegistration.create()
val yandex = YandexProviderRegistration.create()

// Map your AdMob ad unit IDs to Yandex equivalents
AdUnitMapping.register("ca-app-pub-xxx/your-interstitial", mapOf("yandex" to "R-M-XXXXXX-Y"))
AdUnitMapping.register("ca-app-pub-xxx/your-native", mapOf("yandex" to "R-M-XXXXXX-Y"))

// Set provider chains (order = priority)
AdProviderConfig.setInterstitialChain(listOf(admob.interstitialProvider, yandex.interstitialProvider))
AdProviderConfig.setNativeChain(listOf(admob.nativeProvider, yandex.nativeProvider))
// ... same for banner, app open, rewarded

See Multi-Provider Waterfall and Yandex Integration for the full guide.

NativeTemplateView (v2.6.0+)

XML Usage

<com.i2hammad.admanagekit.admob.NativeTemplateView
    android:id="@+id/nativeTemplateView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:adTemplate="material3" />

Available Templates

Template Best For
card_modern General use
material3 M3 apps
minimal Content-focused
compact_horizontal Lists
list_item RecyclerView items
magazine News/blog apps
app_store App promotion (v2.9.0+)
social_feed Feed integration (v2.9.0+)
gradient_card Premium feel (v2.9.0+)
pill_banner Inline placement (v2.9.0+)
medium_horizontal 55/45 media-content split (v3.0.0+)
spotlight High visibility (v2.9.0+)
media_content_split Balanced display (v2.9.0+)
flexible Adaptive layout (v3.3.2+)
icon_left Icon on left, GridView optimized (v3.3.2+)
top_icon_media Icon at top, MediaView center (v3.3.2+)
video_small/medium/large Video content
video_square/vertical/fullscreen Social feeds

Programmatic Usage

// Load with default template
nativeTemplateView.loadNativeAd(activity, "ca-app-pub-xxx/yyy")

// Change template
nativeTemplateView.setTemplate(NativeAdTemplate.MAGAZINE)
nativeTemplateView.loadNativeAd(activity, "ca-app-pub-xxx/yyy")

// With callback
nativeTemplateView.loadNativeAd(activity, adUnitId, object : AdLoadCallback() {
    override fun onAdLoaded() { /* success */ }
    override fun onFailedToLoad(error: AdError?) { /* error */ }
})

// With strategy override
nativeTemplateView.loadNativeAd(activity, adUnitId, callback, AdLoadingStrategy.ONLY_CACHE)

Banner Ads

<com.i2hammad.admanagekit.admob.BannerAdView
    android:id="@+id/bannerAdView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
bannerAdView.loadBanner(this, "ca-app-pub-xxx/yyy")
// Collapsible banner
bannerAdView.loadCollapsibleBanner(this, "ca-app-pub-xxx/yyy", true)

Native Ads (Traditional Views)

<com.i2hammad.admanagekit.admob.NativeBannerSmall
    android:id="@+id/nativeBannerSmall"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
nativeBannerSmall.loadNativeBannerAd(this, "ca-app-pub-xxx/yyy")
// With caching
nativeBannerSmall.loadNativeBannerAd(activity, adUnitId, useCachedAd = true)

Interstitial Ads

// Load
AdManager.getInstance().loadInterstitialAd(this, "ca-app-pub-xxx/yyy")

// Show immediately
AdManager.getInstance().forceShowInterstitial(this, object : AdManagerCallback() {
    override fun onNextAction() { navigateNext() }
})

// Show with dialog
AdManager.getInstance().forceShowInterstitialWithDialog(this, callback)

// Time-based (every 15 seconds)
AdManager.getInstance().showInterstitialAdByTime(this, callback)

// Count-based
AdManager.getInstance().showInterstitialAdByCount(this, callback, maxDisplayCount = 3)

Auto-Reload Configuration (v2.7.0+)

Control whether interstitial ads automatically reload after being shown:

// Global config (applies to all AdManager methods)
AdManageKitConfig.interstitialAutoReload = false  // Disable auto-reload

// Per-call override via InterstitialAdBuilder
InterstitialAdBuilder.with(activity)
    .adUnit(adUnitId)
    .autoReload(true)  // Override global setting for this call
    .show { navigateNext() }

// Per-call override via AdManager
AdManager.getInstance().showInterstitialIfReady(activity, callback, reloadAd = false)

Priority: InterstitialAdBuilder.autoReload() > AdManageKitConfig.interstitialAutoReload

Rewarded Ads

// Initialize once (e.g., in Application.onCreate())
RewardedAdManager.initialize(context, "ca-app-pub-xxx/yyy")

// Show when ready
if (RewardedAdManager.isAdLoaded()) {
    RewardedAdManager.showAd(activity, object : RewardedAdManager.RewardedAdCallback {
        override fun onRewardEarned(rewardType: String, rewardAmount: Int) {
            grantReward(rewardType, rewardAmount)
        }
        override fun onAdDismissed() {
            continueGameFlow()
        }
    })
}

// Load with timeout (splash screens)
RewardedAdManager.loadRewardedAdWithTimeout(context, 5000, callback)

// Preload during natural pauses
RewardedAdManager.preload(context)

// Control auto-reload
AdManageKitConfig.rewardedAutoReload = false  // Disable globally
RewardedAdManager.showAd(activity, callback, autoReload = false)  // Per-call override

App Open Ads

// In Application class
appOpenManager = AppOpenManager(this, "ca-app-pub-xxx/yyy")

// Exclude activities
appOpenManager.disableAppOpenWithActivity(MainActivity::class.java)

// Force show
appOpenManager.forceShowAdIfAvailable(activity, callback)

// Skip next ad
appOpenManager.skipNextAd()

Single-Activity App Support (v3.2.0+)

For apps with one activity and multiple fragments:

// Set current screen when navigating
navController.addOnDestinationChangedListener { _, destination, _ ->
    appOpenManager.setCurrentScreenTag(destination.label?.toString())
}

// Exclude specific screens
appOpenManager.excludeScreenTags("Payment", "Onboarding", "Checkout")

// Or use fragment tag provider
appOpenManager.setFragmentTagProvider {
    supportFragmentManager.fragments.lastOrNull()?.tag
}
appOpenManager.excludeFragmentTags("PaymentFragment", "OnboardingFragment")

// Temporarily disable during critical flows
appOpenManager.disableAppOpenAdsTemporarily()
// ... perform operation ...
appOpenManager.enableAppOpenAds()

Jetpack Compose

@Composable
fun MyScreen() {
    // Banner
    BannerAdCompose(adUnitId = "ca-app-pub-xxx/yyy")

    // NativeTemplateView with any template (v2.6.0+)
    NativeTemplateCompose(
        adUnitId = "ca-app-pub-xxx/yyy",
        template = NativeAdTemplate.MATERIAL3,
        loadingStrategy = AdLoadingStrategy.HYBRID
    )

    // Native with loading strategy (ON_DEMAND or HYBRID only)
    NativeBannerMediumCompose(
        adUnitId = "ca-app-pub-xxx/yyy",
        loadingStrategy = AdLoadingStrategy.HYBRID
    )

    // Interstitial
    val showInterstitial = rememberInterstitialAd(
        adUnitId = "ca-app-pub-xxx/yyy",
        preloadAd = true
    )
    Button(onClick = { showInterstitial() }) {
        Text("Show Ad")
    }

    // Conditional (hides for purchased users)
    ConditionalAd {
        ProgrammaticNativeBannerMediumCompose(adUnitId = "ca-app-pub-xxx/yyy")
    }
}

UMP Consent

AdsConsentManager.getInstance(this).requestUMP(
    activity = this,
    isDebug = true,
    testDeviceId = "TEST_DEVICE_ID",
    resetConsent = false,
    listener = object : UMPResultListener {
        override fun onCheckUMPSuccess(isConsentGiven: Boolean) {
            if (isConsentGiven) {
                // Initialize and load ads here
                AdManager.getInstance().loadInterstitialAd(activity, adUnitId)
            }
        }
    }
)

In-App Purchases (v2.9.0+)

// Define products with categories
val products = listOf(
    PurchaseItem("coins_100", TYPE_IAP.PURCHASE, PurchaseCategory.CONSUMABLE),
    PurchaseItem("remove_ads", TYPE_IAP.PURCHASE, PurchaseCategory.REMOVE_ADS),
    PurchaseItem("lifetime", TYPE_IAP.PURCHASE, PurchaseCategory.LIFETIME_PREMIUM),
    PurchaseItem("premium_monthly", "free_trial", TYPE_IAP.SUBSCRIPTION)
)

// Initialize
AppPurchase.getInstance().initBilling(application, products)

// Purchase
AppPurchase.getInstance().purchase(activity, "remove_ads")

// Subscribe
AppPurchase.getInstance().subscribe(activity, "premium_monthly")

// Check status
if (AppPurchase.getInstance().isPurchased()) {
    // User has premium (subscription, lifetime, or remove_ads)
}

// Track purchases and handle consumables
AppPurchase.getInstance().setPurchaseHistoryListener(object : PurchaseHistoryListener {
    override fun onNewPurchase(productId: String, purchase: PurchaseResult) {
        if (productId == "coins_100") {
            addCoins(100 * purchase.quantity)
            AppPurchase.getInstance().consumePurchase(productId) // Manual consume
        }
    }
    override fun onPurchaseConsumed(productId: String, purchase: PurchaseResult) { }
})

Subscription Management (v2.9.0+)

// Check subscription state
val state = AppPurchase.getInstance().getSubscriptionState("premium_monthly")
when (state) {
    SubscriptionState.ACTIVE -> showPremiumUI()
    SubscriptionState.CANCELLED -> showRenewalPrompt() // Still has access
    SubscriptionState.EXPIRED -> showSubscribeButton()
}

// Upgrade subscription
AppPurchase.getInstance().upgradeSubscription(activity, "premium_yearly")

// Downgrade subscription
AppPurchase.getInstance().downgradeSubscription(activity, "premium_basic")

// Full control with proration mode
AppPurchase.getInstance().changeSubscription(
    activity,
    "premium_monthly",
    "premium_yearly",
    SubscriptionReplacementMode.CHARGE_PRORATED_PRICE
)

Documentation

Wiki

API Documentation (Dokka)

Online: https://i2hammad.github.io/AdManageKit/

Generate locally:

./gradlew dokkaGenerateHtml

Output: build/dokka/html/index.html

MCP Server (AI Integration)

npm

AdManageKit provides an MCP (Model Context Protocol) server that integrates with AI tools like Claude Code, Claude Desktop, Cursor, and other MCP-compatible clients. It provides 10 tools for documentation lookup and code generation.

Tools

Category Tools
Documentation search_docs, get_doc_by_topic, get_api_reference, get_release_notes, get_migration_guide, list_documentation
Code Generation generate_config, generate_ad_integration, generate_billing_code, generate_compose_code

Setup

Claude Desktop / Cursor (claude_desktop_config.json):

{
  "mcpServers": {
    "admanagekit": {
      "command": "npx",
      "args": ["-y", "admanagekit-mcp-server"]
    }
  }
}

Claude Code (auto-configured via .mcp.json when working in this repo):

{
  "mcpServers": {
    "admanagekit": {
      "command": "node",
      "args": ["mcp-server/dist/index.js"]
    }
  }
}

What It Does

  • Search documentation across all docs, wiki pages, and API references
  • Look up API references for any class (AdManager, AppOpenManager, NativeAdManager, etc.)
  • Generate integration code for any ad type with display modes, loading strategies, and callbacks
  • Generate billing code for purchases, subscriptions, consumables, and expiry verification
  • Generate Compose code for all Compose ad components
  • Supports both Kotlin and Java output

See mcp-server/ for more details.


Migration Guide

Migrating to 3.0.0

Version 3.0.0 is fully backward compatible. Optionally adopt new features:

Smart Splash Ads (Recommended)

Replace separate load + show calls with single showOrWaitForAd():

// Before (v2.9.0) - Two-step approach
AdManager.getInstance().loadInterstitialAdForSplash(this, adUnitId, 10_000, object : AdManagerCallback() {
    override fun onNextAction() {
        AdManager.getInstance().forceShowInterstitial(this@SplashActivity, callback)
    }
})

// After (v3.0.0) - Single smart call
AdManager.getInstance().showOrWaitForAd(
    activity = this,
    callback = object : AdManagerCallback() {
        override fun onNextAction() { navigateNext() }
    },
    timeoutMillis = 10_000
)

Ad Pool for Higher Show Rate

// Before (single ad unit)
AdManager.getInstance().loadInterstitialAd(context, "single_unit")

// After (multiple ad units for redundancy)
AdManager.getInstance().loadMultipleAdUnits(context, "high_ecpm", "medium_ecpm", "fallback")

App Open Ad Prefetching

// Prefetch before external intents
appOpenManager.prefetchNextAd()
startActivityForResult(cameraIntent, REQUEST_CODE)

Migrating to 2.9.0

Version 2.9.0 has one breaking change for consumable products:

Consumables are no longer auto-consumed. You must manually call consumePurchase():

// Before v2.9.0 (auto-consume)
AppPurchase.getInstance().setConsumePurchase(true)  // Deprecated

// After v2.9.0 (manual consume)
AppPurchase.getInstance().setPurchaseHistoryListener(object : PurchaseHistoryListener {
    override fun onNewPurchase(productId: String, purchase: PurchaseResult) {
        grantItems(productId, purchase.quantity)
        AppPurchase.getInstance().consumePurchase(productId)  // Manual!
    }
    override fun onPurchaseConsumed(productId: String, purchase: PurchaseResult) { }
})

Use Purchase Categories for better product classification:

// Before
PurchaseItem("coins", TYPE_IAP.PURCHASE, true)  // isConsumable

// After (explicit categories)
PurchaseItem("coins", TYPE_IAP.PURCHASE, PurchaseCategory.CONSUMABLE)
PurchaseItem("remove_ads", TYPE_IAP.PURCHASE, PurchaseCategory.REMOVE_ADS)

Migrating to 2.8.0

Version 2.8.0 is fully backward compatible with one behavioral change:

forceShowInterstitial() now respects loading strategy:

// If you need old behavior (always force fetch), use:
AdManager.getInstance().forceShowInterstitialAlways(activity, callback)

// Or set strategy to ON_DEMAND globally:
AdManageKitConfig.interstitialLoadingStrategy = AdLoadingStrategy.ON_DEMAND

Migrating to 2.7.0

Version 2.7.0 is fully backward compatible. Optionally adopt new features:

// Old way (still works)
val nativeBannerMedium = NativeBannerMedium(context)
nativeBannerMedium.loadNativeBannerAd(activity, adUnitId)

// New unified approach
val nativeTemplateView = NativeTemplateView(context)
nativeTemplateView.setTemplate(NativeAdTemplate.CARD_MODERN)
nativeTemplateView.loadNativeAd(activity, adUnitId)

Sample Project

The app module demonstrates all features. To run:

  1. Clone: git clone https://github.com/i2hammad/AdManageKit.git
  2. Open in Android Studio
  3. Replace placeholder AdMob IDs
  4. Run on device or emulator

Contributing

  1. Fork the repository
  2. Create a branch (git checkout -b feature/YourFeature)
  3. Commit changes (git commit -m 'Add YourFeature')
  4. Push (git push origin feature/YourFeature)
  5. Open a Pull Request

License

Licensed under the MIT License. See LICENSE.

Support

Buy me a coffee

For issues: GitHub Issues or hammadmughal0001@gmail.com

About

AdManageKit is an open-source Android library designed to simplify the management of Google AdMob ads,tROI firebase tracking, in-app billing, and User Messaging Platform (UMP) consent in Android applications.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors