Skip to main content

Troubleshooting Meta Adapter Version Mismatches in AdMob Mediation

 Few logging scenarios are more frustrating for an Android Build Engineer than seeing an ERROR_CODE_MEDIATION_SHOW_ERROR or ClassDefNotFound exception immediately after configuring a mediation network. You have the SDKs installed, the AdMob dashboard is configured, yet the Meta Audience Network (formerly Facebook Audience Network) refuses to fill requests.

The error logs often present as generic "Adapter not found" warnings or crashes pointing to missing methods within com.facebook.ads. This is rarely a configuration error in the AdMob UI. It is almost exclusively a dependency resolution conflict within Gradle, specifically regarding how the Google Mobile Ads (GMA) SDK adapter interacts with the underlying Meta SDK.

The Root Cause: Transitive Dependency Drift

To understand why the adapter fails, we must look at the dependency tree. The AdMob mediation adapter is not a standalone binary; it is a bridge. It is compiled against a specific snapshot of the Meta Audience Network SDK.

When you implement com.google.ads.mediation:facebook, you are pulling in a wrapper that depends transitively on a specific version of the Meta SDK.

The crash or load failure occurs in two primary scenarios:

  1. Explicit Versioning Conflict: You have explicitly defined a version of the Meta SDK (com.facebook.android:audience-network-sdk) in your build.gradle.kts that is newer than what the Google Adapter supports.
  2. Transitive Clash: Another library in your project (e.g., Facebook Login or Share SDK) is pulling in a newer version of the Facebook Core, forcing the Audience Network SDK to upgrade beyond the Adapter's compatibility threshold.

Because the Adapter communicates with the Meta SDK via Java reflection or strict interfaces, a version mismatch results in NoSuchMethodError or ClassNotFoundException at runtime when the Adapter attempts to instantiate the network.

The Solution: Strict Version Alignment

The fix requires strictly aligning the Google Adapter version with the Meta SDK version. Google utilizes a specific versioning scheme for mediation adapters: A.B.C.X.

  • A.B.C: Represents the version of the Meta Audience Network SDK that this adapter supports.
  • X: Represents the Google-specific patch version for the adapter itself.

For example, adapter version 6.17.0.0 is built specifically for Meta Audience Network SDK 6.17.0. If your project forces Meta SDK 6.18.0, the mediation will likely fail.

Step 1: Clean Gradle Implementation (Kotlin DSL)

Remove any standalone com.facebook.android:audience-network-sdk implementations unless you have a specific reason to override the transitive dependency. Rely on the mediation adapter to pull in the correct version.

In your app-level build.gradle.kts:

dependencies {
    // 1. Core Google Mobile Ads SDK
    implementation("com.google.android.gms:play-services-ads:23.0.0")

    // 2. The Meta Adapter
    // Crucial: Check Google's release notes for the latest mapping.
    // As of this writing, 6.17.0.0 maps to Meta SDK 6.17.0
    implementation("com.google.ads.mediation:facebook:6.17.0.0")

    // 3. (Optional) Force resolution if other libs cause conflicts
    // Only use this if you detect other Facebook libraries upgrading the SDK implicitly
    constraints {
        implementation("com.facebook.android:audience-network-sdk:6.17.0") {
            because("AdMob adapter 6.17.0.0 requires this exact binary version")
        }
    }
}

Step 2: Handle R8/ProGuard Obfuscation

A "Class not found" error that appears in Release builds but not Debug builds indicates that R8 (the code shrinker) has stripped the adapter classes because it didn't detect them being used dynamically via reflection by the GMA SDK.

Add the following to your proguard-rules.pro file. This ensures both the Mediation Adapter and the underlying Meta SDK are preserved.

# Keep the AdMob Meta Adapter
-keep class com.google.ads.mediation.facebook.** { *; }

# Keep the Meta Audience Network SDK
-keep class com.facebook.ads.** { *; }

# Prevent warnings regarding okio (common dependency conflict with Meta)
-dontwarn okio.**

Step 3: Lifecycle Integration

The Meta SDK requires initialization. While the GMA SDK handles much of this automatically during mediation, explicit initialization ensures the context is passed correctly before the first ad request.

import android.app.Application
import com.google.android.gms.ads.MobileAds
import com.facebook.ads.AudienceNetworkAds

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // Initialize Meta Audience Network manually to ensure validity
        // This is often required for the adapter to latch on correctly
        AudienceNetworkAds.initialize(this)

        // Initialize AdMob
        MobileAds.initialize(this) { initializationStatus ->
            // Log the status of each adapter to verify integration
            val statusMap = initializationStatus.adapterStatusMap
            val metaStatus = statusMap["com.google.ads.mediation.facebook.FacebookAdapter"]

            if (metaStatus?.initializationState == com.google.android.gms.ads.initialization.AdapterStatus.State.READY) {
                // Adapter is ready
            } else {
                // Log the description to debug specific failures
                // e.g., "Missing manifest configuration" or "Version mismatch"
                System.err.println("Meta Adapter Failed: ${metaStatus?.description}")
            }
        }
    }
}

Deep Dive: Verifying the Fix

After syncing Gradle and rebuilding, you need to verify that the binary linking is successful before pushing to production. Do not rely solely on waiting for a live ad.

Programmatic Verification

Using the adapterStatusMap logic provided in the code above is the most reliable method. If the description returns READY, the class loader successfully linked the Adapter to the SDK. If it returns NOT_READY, check the description string.

Common failure descriptions:

  • "Service not whitelisted/enabled": This is a configuration issue in the AdMob console, not the code.
  • "Adapter signature mismatch" or ClassNotFound: This confirms the Gradle versioning issue persists.

The XML Requirement

Ensure your AndroidManifest.xml contains the required metadata. While not a "version mismatch," missing this causes the adapter to fail initialization, which often mimics a dependency error.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <!-- AdMob App ID -->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
        
        <!-- Crucial for Meta Adapter 6.x+ -->
        <meta-data 
            android:name="com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION" 
            android:value="true"/>
        <meta-data 
            android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING" 
            android:value="true"/>
    </application>
</manifest>

Handling Transitive Exclusion (Advanced)

If your project uses the facebook-android-sdk (the monolithic SDK for Login, Share, and Ads) instead of granular dependencies, you are at high risk of version collision. The monolithic SDK pulls in the latest Audience Network SDK, which will likely break the AdMob adapter.

To fix this, you must exclude the audience network module from the monolithic SDK and let the AdMob adapter provide its preferred version.

dependencies {
    implementation("com.facebook.android:facebook-android-sdk:16.0.0") {
        // Exclude the module that clashes with AdMob's adapter
        exclude(group = "com.facebook.android", module = "audience-network-sdk")
    }
    
    // Now add the adapter, which brings its own compatible version of audience-network-sdk
    implementation("com.google.ads.mediation:facebook:6.17.0.0")
}

Conclusion

When AdMob mediation fails with Meta Audience Network, the issue is rarely the code you wrote in your Activity. It is almost always a mismatch in the Maven dependency graph. By understanding that the Google Adapter is a version-locked wrapper, you can enforce strict versioning in Gradle and configure R8 rules to prevent stripping.

Always prioritize the version mapping provided in the Google Developers release notes over using the absolute latest version of the Meta SDK. Stability in mediation revenue depends on this alignment.