Android

Including the AppLovin MAX Adapter for Android into your app

Ensure that Maven Central is included in your repositories:

repositories {
    // [... other project repos]
    mavenCentral()
}

Update your dependencies to include the latest MobileFuse AppLovin Adapter:

dependencies {
    // [... other project dependencies]
    implementation 'com.mobilefuse.sdk:mobilefuse-adapter-applovin:<<adapterVersionAppLovinAndroid>>'
}

Adapter source code

For reference purposes, the MobileFuse MAX adapter source code is below:

package com.applovin.mediation.adapters;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.Nullable;

import com.applovin.mediation.MaxAdFormat;
import com.applovin.mediation.MaxReward;
import com.applovin.mediation.adapter.MaxAdViewAdapter;
import com.applovin.mediation.adapter.MaxAdapterError;
import com.applovin.mediation.adapter.MaxInterstitialAdapter;
import com.applovin.mediation.adapter.MaxRewardedAdapter;
import com.applovin.mediation.adapter.MaxSignalProvider;
import com.applovin.mediation.adapter.listeners.MaxAdViewAdapterListener;
import com.applovin.mediation.adapter.listeners.MaxInterstitialAdapterListener;
import com.applovin.mediation.adapter.listeners.MaxRewardedAdapterListener;
import com.applovin.mediation.adapter.listeners.MaxSignalCollectionListener;
import com.applovin.mediation.adapter.parameters.MaxAdapterInitializationParameters;
import com.applovin.mediation.adapter.parameters.MaxAdapterParameters;
import com.applovin.mediation.adapter.parameters.MaxAdapterResponseParameters;
import com.applovin.mediation.adapter.parameters.MaxAdapterSignalCollectionParameters;
import com.applovin.sdk.AppLovinSdk;
import com.applovin.sdk.AppLovinSdkConfiguration;
import com.applovin.sdk.AppLovinSdkUtils;
import com.mobilefuse.adapter.applovin.BuildConfig;
import com.mobilefuse.sdk.AdError;
import com.mobilefuse.sdk.MobileFuse;
import com.mobilefuse.sdk.MobileFuseBannerAd;
import com.mobilefuse.sdk.MobileFuseInterstitialAd;
import com.mobilefuse.sdk.MobileFuseRewardedAd;
import com.mobilefuse.sdk.SdkInitListener;
import com.mobilefuse.sdk.internal.MobileFuseBiddingTokenProvider;
import com.mobilefuse.sdk.internal.MobileFuseBiddingTokenRequest;
import com.mobilefuse.sdk.internal.TokenGeneratorListener;
import com.mobilefuse.sdk.privacy.MobileFusePrivacyPreferences;

import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;

public class MobileFuseMediationAdapter
        extends MediationAdapterBase
        implements MaxAdViewAdapter, MaxInterstitialAdapter, MaxRewardedAdapter, MaxSignalProvider
{
    // Server parameters
    private static final String PARAM_NAME_APP_KEY = "app_id";
    private static final String PARAM_NAME_CUSTOM_PARAMS_JSON = "custom_parameters";
    private static final String PARAM_NAME_BG_COLOR = "background_color";
    private static final String PARAM_NAME_INITIALLY_MUTED = "initially_muted";
    
    // State
    private static final AtomicBoolean initialized = new AtomicBoolean();
    
    // Ad objects
    private MobileFuseBannerAd bannerAd;
    private MobileFuseInterstitialAd interstitialAd;
    private MobileFuseRewardedAd rewardedAd;
    
    public MobileFuseMediationAdapter(AppLovinSdk appLovinSdk)
    {
        super( appLovinSdk );
        log( "Create MobileFuse MAX adapter." );
    }
    
    @Override
    public void initialize(MaxAdapterInitializationParameters parameters, Activity activity, OnCompletionListener onCompletionListener)
    {
        log( "Initializing SDK..." );
        
        if ( initialized.get() )
        {
            log( "SDK is already initialized" );
            onCompletionListener.onCompletion( InitializationStatus.INITIALIZED_SUCCESS, null );
            return;
        }
        
        Bundle serverParameters = parameters.getServerParameters();
        final String appKey = serverParameters.getString( PARAM_NAME_APP_KEY, null );
        
        if ( appKey == null || appKey.isEmpty() )
        {
            log( "No app key is set for initialization, running with bidding support only" );
            onCompletionListener.onCompletion( InitializationStatus.INITIALIZED_SUCCESS, null );
            return;
        }
        
        SdkInitListener listener = new SdkInitListener()
        {
            @Override
            public void onInitSuccess()
            {
                log( "MobileFuse SDK initialized" );
                initialized.set( true );
                onCompletionListener.onCompletion( InitializationStatus.INITIALIZED_SUCCESS, null );
            }
            
            @Override
            public void onInitError()
            {
                log( "MobileFuse SDK failed to initialize" );
                onCompletionListener.onCompletion( InitializationStatus.INITIALIZED_FAILURE, "failed to initialize MobileFuse sdk" );
            }
        };
        
        log( "Initializing MobileFuse SDK with App Key: '" + appKey + "'..." );
        MobileFuse.init( obtainApplicationContext( activity ), appKey, listener );
    }
    
    @Override
    public String getSdkVersion()
    {
        return MobileFuse.getSdkVersion();
    }
    
    @Override
    public String getAdapterVersion()
    {
        return BuildConfig.VERSION_NAME;
    }
    
    @Override
    public void onDestroy()
    {
        log( "Destroying adapter" );
        if ( bannerAd != null )
        {
            bannerAd.destroy();
            bannerAd = null;
        }
        
        interstitialAd = null;
        rewardedAd = null;
    }
    
    //region MAX Signal Provider Methods
    
    @Override
    public void collectSignal(MaxAdapterSignalCollectionParameters parameters, Activity activity, MaxSignalCollectionListener callback)
    {
        try
        {
            Context context = getContext( activity );
            
            MobileFuseBiddingTokenRequest tokenRequest = getBiddingTokenRequest( parameters );
            MobileFuseBiddingTokenProvider.getToken(
                    tokenRequest,
                    context,
                    new TokenGeneratorListener()
                    {
                        @Override
                        public void onTokenGenerated(String token)
                        {
                            callback.onSignalCollected( token );
                        }
                        
                        @Override
                        public void onTokenGenerationFailed(String error)
                        {
                            callback.onSignalCollectionFailed( error );
                        }
                    }
            );
        }
        catch ( Throwable e )
        {
            callback.onSignalCollectionFailed( "Failed to generate bidding token with internal error " + e );
        }
    }
    
    //endregion
    
    //region MAX Interstitial Adapter Methods
    
    @Override
    public void loadInterstitialAd(MaxAdapterResponseParameters parameters, Activity activity, MaxInterstitialAdapterListener listener)
    {
        String bidResponse = parameters.getBidResponse();
        boolean isBidding = AppLovinSdkUtils.isValidString( bidResponse );
        String placementId = parameters.getThirdPartyAdPlacementId();
        log( "Loading " + (isBidding ? "bidding " : "") + "interstitial ad for placement: '" + placementId + "'..." );
        
        interstitialAd = new MobileFuseInterstitialAd( activity, placementId );
        interstitialAd.setListener( createMobileFuseAdListener( listener ) );
        
        if ( isBidding )
        {
            interstitialAd.loadAdFromBiddingToken( bidResponse );
        }
        else
        {
            interstitialAd.loadAd();
        }
    }
    
    @Override
    public void showInterstitialAd(MaxAdapterResponseParameters parameters, Activity activity, MaxInterstitialAdapterListener listener)
    {
        log( "Showing interstitial ad: '" + parameters.getThirdPartyAdPlacementId() + "'..." );
        
        if ( interstitialAd == null || !interstitialAd.isLoaded() )
        {
            log( "Unable to show interstitial - no ad loaded" );
            listener.onInterstitialAdDisplayFailed( MaxAdapterError.AD_NOT_READY );
            return;
        }
        
        interstitialAd.showAd();
    }
    
    //endregion
    
    //region MAX Rewarded Adapter Methods
    
    @Override
    public void loadRewardedAd(MaxAdapterResponseParameters parameters, Activity activity, MaxRewardedAdapterListener listener)
    {
        String bidResponse = parameters.getBidResponse();
        boolean isBidding = AppLovinSdkUtils.isValidString( bidResponse );
        String placementId = parameters.getThirdPartyAdPlacementId();
        log( "Loading " + (isBidding ? "bidding " : "") + "interstitial ad for placement: '" + placementId + "'..." );
        
        rewardedAd = new MobileFuseRewardedAd( activity, placementId );
        rewardedAd.setListener( createMobileFuseAdListener( listener ) );
        
        if ( isBidding )
        {
            rewardedAd.loadAdFromBiddingToken( bidResponse );
        }
        else
        {
            rewardedAd.loadAd();
        }
    }
    
    @Override
    public void showRewardedAd(MaxAdapterResponseParameters parameters, Activity activity, MaxRewardedAdapterListener listener)
    {
        log( "Showing rewarded ad: '" + parameters.getThirdPartyAdPlacementId() + "'..." );
        
        if ( rewardedAd == null || !rewardedAd.isLoaded() )
        {
            log( "Unable to show rewarded ad - no ad loaded" );
            listener.onRewardedAdDisplayFailed( MaxAdapterError.AD_NOT_READY );
            return;
        }
        
        rewardedAd.showAd();
    }
    
    //endregion
    
    //region MAX Ad View Adapter Methods
    
    @Override
    public void loadAdViewAd(MaxAdapterResponseParameters parameters, MaxAdFormat adFormat, Activity activity, MaxAdViewAdapterListener listener)
    {
        String bidResponse = parameters.getBidResponse();
        boolean isBidding = AppLovinSdkUtils.isValidString( bidResponse );
        String placementId = parameters.getThirdPartyAdPlacementId();
        log( "Loading " + (AppLovinSdkUtils.isValidString( bidResponse ) ? "bidding " : "") + adFormat.getLabel() + " for placement: '" + placementId + "'..." );
    
        Context context = getContext( activity );
        bannerAd = new MobileFuseBannerAd( context, placementId, convertMaxFormatToAdSize( adFormat ) );
        bannerAd.setListener( createMobileFuseAdListener( listener ) );
    
        Bundle serverParameters = parameters.getServerParameters();
        if ( serverParameters != null )
        {
            Boolean initiallyMuted = getCustomParamBooleanValue( serverParameters, PARAM_NAME_INITIALLY_MUTED );
            if ( initiallyMuted != null )
            {
                bannerAd.setMuted( initiallyMuted );
            }
    
            ColorDrawable customBackground = parseColor( getCustomParamStringValue( serverParameters, PARAM_NAME_BG_COLOR ) );
            if ( customBackground != null )
            {
                bannerAd.setBackground( customBackground );
            }
        }
        
        if ( isBidding )
        {
            bannerAd.loadAdFromBiddingToken( bidResponse );
        }
        else
        {
            bannerAd.loadAd();
        }
    }
    
    //endregion
    
    //region MAX Parameter Parsing
    
    private MobileFuseBiddingTokenRequest getBiddingTokenRequest(MaxAdapterParameters parameters)
    {
        MobileFusePrivacyPreferences.Builder builder = new MobileFusePrivacyPreferences.Builder();
        
        builder.setSubjectToGdpr( getWrappingSdk().getConfiguration().getConsentDialogState() == AppLovinSdkConfiguration.ConsentDialogState.APPLIES );
        
        if ( AppLovinSdk.VERSION_CODE >= 91100 )
        {
            Boolean isDoNotSell = getPrivacySetting( "isDoNotSell", parameters );
            if ( isDoNotSell != null )
            {
                builder.setUsPrivacyConsentString( isDoNotSell ? "1YY-" : "1YN-" );
            }
            else
            {
                builder.setUsPrivacyConsentString( "1---" );
            }
        }
        
        if ( AppLovinSdk.VERSION_CODE >= 11_04_03_99 )
        {
            if ( parameters.getConsentString() != null )
            {
                builder.setIabConsentString( parameters.getConsentString() );
            }
        }
        
        Boolean isAgeRestrictedUser = getPrivacySetting( "isAgeRestrictedUser", parameters );
        if ( isAgeRestrictedUser != null )
        {
            builder.setSubjectToCoppa( isAgeRestrictedUser );
        }
        
        boolean isTesting = parameters.isTesting();
        
        return new MobileFuseBiddingTokenRequest( builder.build(), isTesting );
    }
    
    private Boolean getPrivacySetting(final String privacySetting, final MaxAdapterParameters parameters)
    {
        try
        {
            // Use reflection because compiled adapters have trouble fetching `boolean` from old SDKs and `Boolean` from new SDKs (above 9.14.0)
            Class<?> parametersClass = parameters.getClass();
            Method privacyMethod = parametersClass.getMethod( privacySetting );
            return (Boolean) privacyMethod.invoke( parameters );
        }
        catch ( Exception exception )
        {
            log( "Error getting privacy setting " + privacySetting + " with exception: ", exception );
            return (AppLovinSdk.VERSION_CODE >= 9140000) ? null : false;
        }
    }
    
    private Bundle getServerCustomParams(Bundle serverParameters)
    {
        if ( !serverParameters.containsKey( PARAM_NAME_CUSTOM_PARAMS_JSON ) )
        {
            return null;
        }
        return serverParameters.getBundle( PARAM_NAME_CUSTOM_PARAMS_JSON );
    }
    
    private String getCustomParamStringValue(Bundle serverParameters, String customParamName)
    {
        try
        {
            Bundle customParams = getServerCustomParams( serverParameters );
            if ( customParams == null )
            {
                return null;
            }
            if ( !customParams.containsKey( customParamName ) )
            {
                return null;
            }
            return customParams.getString( customParamName ).trim();
        }
        catch ( Exception ex )
        {
            ex.printStackTrace();
        }
        return null;
    }
    
    private Boolean getCustomParamBooleanValue(Bundle serverParameters, String customParamName)
    {
        try
        {
            Bundle customParams = getServerCustomParams( serverParameters );
            if ( customParams == null )
            {
                return null;
            }
            if ( !customParams.containsKey( customParamName ) )
            {
                return null;
            }
            return customParams.getBoolean( customParamName );
        }
        catch ( Exception ex )
        {
            ex.printStackTrace();
        }
        return null;
    }
    
    //endregion
    
    //region Data conversion helpers
    
    private MobileFuseBannerAd.AdSize convertMaxFormatToAdSize(MaxAdFormat adFormat)
    {
        if ( adFormat == MaxAdFormat.LEADER )
        {
            return MobileFuseBannerAd.AdSize.BANNER_728x90;
        }
        else if ( adFormat == MaxAdFormat.MREC )
        {
            return MobileFuseBannerAd.AdSize.BANNER_300x250;
        }
        else
        {
            return MobileFuseBannerAd.AdSize.BANNER_320x50;
        }
    }
    
    //endregion
    
    //region Helper methods
    
    private Context obtainApplicationContext(Activity activity)
    {
        return (activity != null)
                ? activity.getApplicationContext()
                : getApplicationContext();
    }
    
    private ColorDrawable parseColor(String backgroundColorValue)
    {
        if ( backgroundColorValue == null )
        {
            return null;
        }
        
        if ( backgroundColorValue.startsWith( "#" ) )
        {
            backgroundColorValue = backgroundColorValue.substring( 1 );
        }
        else if ( backgroundColorValue.startsWith( "0x" ) )
        {
            backgroundColorValue = backgroundColorValue.substring( 2 );
        }
        
        if ( backgroundColorValue.length() <= 6 )
        {
            backgroundColorValue = "ff" + backgroundColorValue;
        }
        
        try
        {
            return new ColorDrawable((int) Long.parseLong( backgroundColorValue, 16 ));
        }
        catch ( NumberFormatException ex )
        {
            return null;
        }
    }
    
    private Context getContext(@Nullable Activity activity)
    {
        // NOTE: `activity` can only be null in 11.1.0+, and `getApplicationContext()` is introduced in 11.1.0
        return ( activity != null ) ? activity.getApplicationContext() : getApplicationContext();
    }
    
    //endregion
    
    //region Listener creation methods
    
    private MobileFuseInterstitialAd.Listener createMobileFuseAdListener(MaxInterstitialAdapterListener maxListener)
    {
        return new MobileFuseInterstitialAd.Listener()
        {
            @Override
            public void onAdClosed()
            {
                log( "InterstitialAd::onAdClosed" );
                maxListener.onInterstitialAdHidden();
            }
            
            @Override
            public void onAdLoaded()
            {
                log( "InterstitialAd::onAdLoaded" );
                maxListener.onInterstitialAdLoaded();
            }
            
            @Override
            public void onAdNotFilled()
            {
                log( "InterstitialAd::onAdNotFilled" );
                maxListener.onInterstitialAdLoadFailed( MaxAdapterError.NO_FILL );
            }
            
            @Override
            public void onAdRendered()
            {
                log( "InterstitialAd::onAdRendered" );
                maxListener.onInterstitialAdDisplayed();
            }
            
            @Override
            public void onAdClicked()
            {
                log( "InterstitialAd::onAdClicked" );
                maxListener.onInterstitialAdClicked();
            }
            
            @Override
            public void onAdExpired()
            {
                log( "InterstitialAd::onAdExpired" );
                maxListener.onInterstitialAdLoadFailed( MaxAdapterError.AD_EXPIRED );
            }
            
            @Override
            public void onAdError(AdError adError)
            {
                if ( adError != null )
                {
                    log( "InterstitialAd::onAdError [adErrorCode" + adError.getErrorCode() + ", adErrorMsg: " + adError.getErrorMessage() + "]" );
                }
                else
                {
                    log( "InterstitialAd::onAdError" );
                }
            }
        };
    }
    
    private MobileFuseRewardedAd.Listener createMobileFuseAdListener(MaxRewardedAdapterListener maxListener)
    {
        return new MobileFuseRewardedAd.Listener()
        {
            @Override
            public void onAdClosed()
            {
                log( "RewardedAd::onAdClosed" );
                maxListener.onRewardedAdHidden();
            }
            
            @Override
            public void onUserEarnedReward()
            {
                log( "RewardedAd::onUserEarnedReward" );
                maxListener.onUserRewarded( new MaxReward()
                {
                    @Override
                    public String getLabel()
                    {
                        return "";
                    }
                    
                    @Override
                    public int getAmount()
                    {
                        return 0;
                    }
                } );
            }
            
            @Override
            public void onAdLoaded()
            {
                log( "RewardedAd::onAdLoaded" );
                maxListener.onRewardedAdLoaded();
            }
            
            @Override
            public void onAdNotFilled()
            {
                log( "RewardedAd::onAdNotFilled" );
                maxListener.onRewardedAdLoadFailed( MaxAdapterError.NO_FILL );
            }
            
            @Override
            public void onAdRendered()
            {
                log( "RewardedAd::onAdRendered" );
                maxListener.onRewardedAdDisplayed();
            }
            
            @Override
            public void onAdClicked()
            {
                log( "RewardedAd::onAdClicked" );
                maxListener.onRewardedAdClicked();
            }
            
            @Override
            public void onAdExpired()
            {
                log( "RewardedAd::onAdExpired" );
                maxListener.onRewardedAdLoadFailed( MaxAdapterError.AD_EXPIRED );
            }
            
            @Override
            public void onAdError(AdError adError)
            {
                if ( adError != null )
                {
                    log( "RewardedAd::onAdError [adErrorCode" + adError.getErrorCode() + ", adErrorMsg: " + adError.getErrorMessage() + "]" );
                }
                else
                {
                    log( "RewardedAd::onAdError" );
                }
            }
        };
    }
    
    private MobileFuseBannerAd.Listener createMobileFuseAdListener(MaxAdViewAdapterListener listener)
    {
        return new MobileFuseBannerAd.Listener()
        {
            @Override
            public void onAdExpanded()
            {
                log( "BannerAd::onAdExpanded" );
                listener.onAdViewAdExpanded();
            }
            
            @Override
            public void onAdCollapsed()
            {
                log( "BannerAd::onAdCollapsed" );
                listener.onAdViewAdCollapsed();
            }
            
            @Override
            public void onAdLoaded()
            {
                log( "BannerAd::onAdLoaded" );
                listener.onAdViewAdLoaded( bannerAd );
            }
            
            @Override
            public void onAdNotFilled()
            {
                log( "BannerAd::onAdNotFilled" );
                listener.onAdViewAdLoadFailed( MaxAdapterError.NO_FILL );
            }
            
            @Override
            public void onAdRendered()
            {
                log( "BannerAd::onAdRendered" );
                listener.onAdViewAdDisplayed();
            }
            
            @Override
            public void onAdClicked()
            {
                log( "BannerAd::onAdClicked" );
                listener.onAdViewAdClicked();
            }
            
            @Override
            public void onAdExpired()
            {
                log( "BannerAd::onAdExpired" );
                listener.onAdViewAdLoadFailed( MaxAdapterError.AD_EXPIRED );
            }
            
            @Override
            public void onAdError(AdError adError)
            {
                if ( adError != null )
                {
                    log( "BannerAd::onAdError [adErrorCode" + adError.getErrorCode() + ", adErrorMsg: " + adError.getErrorMessage() + "]" );
                }
                else
                {
                    log( "BannerAd::onAdError" );
                }
                listener.onAdViewAdDisplayFailed( MaxAdapterError.INTERNAL_ERROR );
            }
        };
    }
    
    //endregion
    
}