How to integrate UniConsent CMP SDK for Android with mobile apps

UniConsent CMP is a package for handling GDPR IAB TCF 2.3 consent management in Android apps. You can find a demo app integrated with UniConsent CMP in the "demo" directory.

Prerequisites

  • UniConsent CMP plan with Mobile app support
  • Android API level 21 or higher
  • UniConsent CMP SDK package (request from support)

Getting started

Add UniConsentSDK-release.aar into your project's libs/ directory and update your build.gradle:

implementation files('libs/UniConsentSDK-release.aar')
implementation 'androidx.appcompat:appcompat:1.7.1'
implementation 'com.google.android.material:material:1.13.0'
implementation 'com.iabtcf:iabtcf-core:2.0.10'
implementation 'com.iabtcf:iabtcf-decoder:2.0.10'

Before integrating the SDK, customize the consent banner appearance in the UniConsent Dashboard to match your brand and optimize consent rates.

Step 1: Brand Styling in Dashboard

Go to Projects → Select your Project → Settings → Step 5: UI & Style Settings to configure:

  • Main Button Colour — Set the primary action button color to match your brand
  • Main Button Text Colour — Adjust text color on the primary button for readability
  • Background Colour — Set the banner background color to blend with your app
  • Text Colour — Ensure body text has appropriate contrast

Step 2: Advanced Styling with Custom CSS (Optional)

For more precise control, add custom CSS in the CSS Content field under Step 5. This is recommended to make the banner feel native to your app and achieve the best consent rate:

/* Example: Style the accept button to match your brand */
.unic-btn-accept {
  background-color: #4CAF50;
  border-radius: 8px;
  font-weight: 600;
}

/* Example: Adjust banner font */
.unic-banner {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Example: Make the reject button less prominent */
.unic-btn-reject {
  background-color: transparent;
  border: 1px solid #ccc;
  color: #666;
}

Tip: A well-branded consent UI that feels native to your app typically achieves higher consent rates. Users are more likely to engage positively with a banner that matches the look and feel they expect.

Usage

To use the UniConsent CMP in your app, follow these steps:

Initialize the CMP with an App ID from your account manager:

UniConsent UniConsentCMP = UniConsent.getInstance();
UniConsentCMP.setAppId("YOUR_APP_ID");

Display the CMP UI:

// Display CMP as full-screen page (default)
UniConsent.getInstance().launchCMP();

// Display CMP as a modal bottom sheet
UniConsent.getInstance().launchCMP(CMPDisplayMode.BOTTOM_SHEET);

// Display CMP as a center dialog
UniConsent.getInstance().launchCMP(CMPDisplayMode.DIALOG);

You can also launch with a specific stage and display mode:

// Launch at a specific stage with a display mode
UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen, CMPDisplayMode.BOTTOM_SHEET);

// Or set a default display mode for all launches
UniConsent.getInstance().setDisplayMode(CMPDisplayMode.BOTTOM_SHEET);
UniConsent.getInstance().launchCMP();

Automatically check if consent is expired when the vendorList updates:

// Check if consent should be requested (e.g. first visit, or vendor list updated)
if (UniConsentCMP.shouldRequestConsent()) {
    UniConsentCMP.launchCMP();
}

Get the tcString if required:

// Get tcString
UniConsent.getInstance().getTCString();

Read the consent status:

// Read consent status
UniConsent.getInstance().hasIABPurposeConsent(1);
UniConsent.getInstance().hasIABVendorConsent(1);

Reset consent status if required:

// Reset consent status
UniConsent.getInstance().clearData();

Example of using AppCompatActivity

import com.uniconsent.sdk.CMPDisplayMode;
import com.uniconsent.sdk.Event;
import com.uniconsent.sdk.EventHandler;
import com.uniconsent.sdk.Stage;
import com.uniconsent.sdk.UniConsent;

public class MainActivity extends AppCompatActivity implements EventHandler {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        UniConsent UniConsentCMP = UniConsent.getInstance();
        UniConsentCMP.setAppId("YOUR_APP_ID");
        UniConsentCMP.init(this);
        // register callback events
        UniConsentCMP.subscribe(this);
        // check if consent should be requested
        if (UniConsentCMP.shouldRequestConsent()) {
            UniConsentCMP.launchCMP();
        }
    }

    public void openUniConsentUI(View view) {
        // Full screen
        UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen);
    }

    public void openAsBottomSheet(View view) {
        // Bottom sheet
        UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen, CMPDisplayMode.BOTTOM_SHEET);
    }

    public void openAsDialog(View view) {
        // Center dialog
        UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen, CMPDisplayMode.DIALOG);
    }

    @Override
    public void handle(Event event) {
        UniConsent.getInstance().hasIABVendorConsent(1);
    }
}

Example of using ComponentActivity

package com.example.myapplication

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.uniconsent.sdk.CMPDisplayMode
import com.uniconsent.sdk.Event
import com.uniconsent.sdk.EventHandler
import com.uniconsent.sdk.Stage
import com.uniconsent.sdk.UniConsent

class MainActivity : ComponentActivity(), EventHandler {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val cmp = UniConsent.getInstance()
        cmp.appId = "YOUR_APP_ID"
        cmp.init(this)
        cmp.subscribe(this)

        if (cmp.shouldRequestConsent()) {
             cmp.launchCMP();
        }
        setContent {
            MyApplicationTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Column(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(16.dp),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Button(onClick = {
                            UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen)
                        }) {
                            Text("Privacy Settings")
                        }
                        Spacer(modifier = Modifier.height(16.dp))
                        Button(onClick = {
                            UniConsent.getInstance().launchCMP(
                                Stage.GDPRFirstScreen, CMPDisplayMode.BOTTOM_SHEET
                            )
                        }) {
                            Text("Privacy Settings (Bottom Sheet)")
                        }
                        Spacer(modifier = Modifier.height(16.dp))
                        Button(onClick = {
                            UniConsent.getInstance().launchCMP(
                                Stage.GDPRFirstScreen, CMPDisplayMode.DIALOG
                            )
                        }) {
                            Text("Privacy Settings (Dialog)")
                        }
                    }
                }
            }
        }
    }

    override fun handle(event: Event?) {
        Log.d("CMP_EVENT", event.toString())
        UniConsent.getInstance().hasIABVendorConsent(1)
    }
}

Permission

<uses-permission android:name="android.permission.INTERNET" />

Setup default consent status KV:

<meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />

<meta-data android:name="google_analytics_default_allow_analytics_storage" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_storage" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_user_data" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_personalization_signals" android:value="false" />

Control analytics based on the consent flags:


// <= 25.6.1
override fun handle(event: Event?) {
    Log.d("CMP_EVENT", event.toString())
    if(UniConsent.getInstance().hasIABPurposeConsent(1)) {
        // Set consent types.
        Map<FirebaseAnalytics.ConsentType, FirebaseAnalytics.ConsentStatus> consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class);
        consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, FirebaseAnalytics.ConsentStatus.GRANTED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, FirebaseAnalytics.ConsentStatus.GRANTED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, FirebaseAnalytics.ConsentStatus.GRANTED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, FirebaseAnalytics.ConsentStatus.GRANTED);

        mFirebaseAnalytics.setConsent(consentMap);
        mFirebaseAnalytics.setAnalyticsCollectionEnabled(true);
    } else {
        // Set consent types.
        Map<FirebaseAnalytics.ConsentType, FirebaseAnalytics.ConsentStatus> consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class);
        consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, FirebaseAnalytics.ConsentStatus.DENIED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, FirebaseAnalytics.ConsentStatus.DENIED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, FirebaseAnalytics.ConsentStatus.DENIED);
        consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, FirebaseAnalytics.ConsentStatus.DENIED);

        mFirebaseAnalytics.setConsent(consentMap);
        mFirebaseAnalytics.setAnalyticsCollectionEnabled(false);
    }

    // other logics such as send analytics events
}

// > 25.6.1
override fun handle(event: Event?) {
    Log.d("CMP_EVENT", event.toString())

    // other logics such as send analytics events

    // Example: send Firebase event or other analytics metrics
    Bundle bundle = new Bundle();
    bundle.putString(FirebaseAnalytics.Param.ITEM_ID, "id");
    bundle.putString(FirebaseAnalytics.Param.ITEM_NAME, "name");
    bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, "image");
    mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle);
}

Find more info at Set up consent mode for apps

Display Modes

The SDK supports three display modes for the consent UI, matching the Flutter SDK API:

ModeEnumDescription
Full ScreenCMPDisplayMode.FULL_SCREENOpens CMP in a new full-screen activity (default)
Bottom SheetCMPDisplayMode.BOTTOM_SHEETSlides up from the bottom as a modal sheet (85% height)
DialogCMPDisplayMode.DIALOGDisplays as a centered dialog (90% width, 75% height)

Note: Bottom sheet and dialog modes require your Activity to extend AppCompatActivity or FragmentActivity.

Notes

  1. Users should have the ability to access a "Privacy Settings" button or link in the settings section of your application in order to open the CMP UI.
  2. You can utilize the shouldRequestConsent() function to check whether you should request new consent based on the status. Display the CMP UI as needed when a user opens the application.
  3. Starting with SDK version 25.6.1, you no longer need to manually send consent options for FirebaseAnalytics or certain supported AAP SDKs — they are handled automatically by the SDK. For more information, see What is Google AAP and Google MMP for Mobile Apps?.