Info
Content

[Android] 1. consentmanager SDK Integration

The consentmanager SDK for Android apps implements and provides functionality to inform the user about data protection and ask and collect consent from the user. It enables app-developers to easily integrate the consentmanager service into their app.

How it works

  1. Integrate the SDK into the app and configure the SDK settings
  2. Once the SDK is intergated into an app, the SDK will provide functions for the app developer in order to retrieve consent data
  3. As soon as the app starts, the SDK will automatically retrieve information from the consentmanager servers in order to prepare the SDK for its usage.
  4. It is recommended, that on startup of the app, the app creates an instance of class CMPConsentTool. Once the this is created, the SDK will automatically show the consent screen if necessary.
  5. When the app wants to process personal data, it should "ask" the SDK if consent was given for the specific purpose and vendor.

Installation

Since Version 1.7.0 The SDK repository has been moved to the official Maven repository. The migration Guide can be found here

Find the compatible native SDK Versions here.

Gradle

Add the dependency to your apps build.gradle. (To always get the latest version use the + symbol to get the newest updates. You can for example always get the newest versions for minor updates through 1.x.+)

dependencies {
  implementation 'net.consentmanager.sdk:android:x.xx.x'
}

Maven

Add the dependency to your apps build.gradle. (To always get the latest version in maven you can use different methods to decline the version range. you can look them up here )

<dependency>
    <groupId>net.consentmanager.sdk</groupId>
    <artifactId>android</artifactId>
    <version>x.xx.x</version>
</dependency>

Using the library

Permissions

This SDK requires the following permissions, please ensure to add them to your AndroidManifest.xml:

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

Initiate ConsentTool

With the app-start (usually your viewDidAppear function) you must create an instance of class CMPConsentTool. This will automatically fetch the necessary data from our server and determine if the consent screen needs to be shown or not. If so, the SDK will automatically show the consent screen at this point, collect the data and provide the data to the app. The instance can then be used in order to get consent details from the SDK in order to use it in the app.

To initiate the ConsentTool, go to your targeted class and create a instance of CMPConsentTool like shown below:

class CmpDemoActivity : FragmentActivity() {

    private lateinit var cmpManager: CmpManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val config = CmpConfig.apply {
            id ="yourid"
            domain = ConsentActivity.CMP_DOMAIN
            appName = ConsentActivity.CMP_APP_NAME
            language = ConsentActivity.LANG
        }
        cmpManager = CmpManager.createInstance(this, config)
        cmpManager.initialize(this)
    }
// Java example instantiation: 

    CmpManager cmpManager = null;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CmpConfig cmpConfig = CmpConfig.INSTANCE;
        cmpConfig.setId("YourId");
        cmpConfig.setDomain("delivery.consentmanager.net");
        cmpConfig.setAppName("YourAppName");
        cmpConfig.setLanguage("EN");
        cmpConfig.setTimeout(4000);
        cmpManager = CmpManager.createInstance(this, cmpConfig);
      
    }

// ... open layer and asking for purpose:

        cmpManager.openConsentLayer(getApplication());
        if (cmpManager.hasPurposeConsent("PURPOSE_ID")) {
            Log.d(TAG, "has purpose");
        }

In order to create the instance of CMPConsentTool you need to configure the instance. You will need to provide the CODE-ID, server domain , an app name and a language. The CODE-ID and server domain can be found in your consentmanager account under Menu > Get Code. The app name can be used in order to distinguis different apps in the consentmanager reporting. For the language you can either use an empty string ("") for auto-detection or a 2-letter language code ("EN", "DE", "FR" and so on).

The configuration values can be inserted via different ways:

a) SDK-Configuration via CmpConfig

Add the following lines to your code:

val config = CmpConfig.apply { 
            serverDomain = CMP_DOMAIN
            appName = CMP_APP_NAME
            language = LANG
            id = CODE_ID
        }
cmpManager = CmpManager.createInstance(this, config)
b) SDK-Configuration via createInstance()

Add the following line to your code:

        cmpManager =
            CmpManager.createInstance(
                this,
                config.id,
                config.domain,
                config.appName,
                config.language
            )

Initializing and opening the consent layer

To check if the user need to give consent and to open the consent layer, there a various options. 

By Initialize call

The initialize function is designed to set up the CMP SDK within your application context and automatically check and open the consent layer if required. The initialize can be chained to the instance creation

cmpManager = CmpManager.createInstance(this, config).initialize(this)
By CheckAndOpen call

Similar as the initialize function the CheckAndOpenLayer will open the consent layer if required. 

 cmpManager.checkAndOpenConsentLayer(this)
Manually

The check function offers a manual approach to determine if user consent is required. It allows for a callback mechanism and an optional cache mechanism to reduce network requests.

        cmpManager.check({ isConsentRequired ->
            if (isConsentRequired) {
                // Consent is required, handle accordingly
                runOnUiThread {
                    // Update UI or show consent dialog
                    cmpManager.openLayer()
                }
            } else {
                // Consent is not required, proceed with application logic
            }
        }, isCached = true)

Creating a custom layout

For creating a custom layout you can use the CmpUIConfig class with different styling options. This class offers also some preset layouts like 

  • configureHalfScreenBottom
  • configureHalfScreenTop
  • configureCenterScreen
  • configureSmallCenterScreen
  • configureLargeTopScreen
  • configureLargeBottomScreen

For creating a custom layout the CMP SDK offers also different strategies:

  • Dialog Window
  • Popup Window
  • Fragment

You can change the strategy by setting the UIConfig parameter: 

CmpUIConfig.uiStrategy = CmpUIStrategy.DIALOG
CmpUIConfig.uiStrategy = CmpUIStrategy.POPUP
CmpUIConfig.uiStrategy = CmpUIStrategy.ACTIVITY
CmpUIConfig.uiStrategy = CmpUIStrategy.FRAGMENT

We recommend to use a Popup Window which is also set as default since version 2.3.0

Two important parameter will determine the Popup and Dialog behaviour: 

Popup behaviour
Parameter isFocusable = true isFocusable = false
isOutsideTouchable =  true Dismisses on outside touch. Can gain focus for input events. Dismisses on outside touch. Does not gain focus or intercept keyboard input.
isOutsideTouchable = false Does not dismiss on outside touch. Can gain focus and intercept input events. Does not dismiss on outside touch. Does not gain focus or intercept keyboard input.

 

 

 

Dialog behaviour
Parameter isFocusable = true isFocusable = false
isOutsideTouchable =  true Dismisses on outside touch (setCanceledOnTouchOutside(true)). Dialog is focusable by default. Dialog does not dismiss on outside touch and might not behave as expected since dialogs are typically focusable.
isOutsideTouchable = false Does not dismiss on outside touch (setCanceledOnTouchOutside(false)). Dialog remains focusable and can intercept input events. Dialog does not dismiss on outside touch and might not behave as expected due to the lack of focusability.
Example for Fragment:
R.id.cmpContainer is a Framelayout which could look like this in the activity layout xml in layout/{your_activity}.xml

<FrameLayout
    android:id="@+id/cmpContainer"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    android:translationZ="90dp"
    app:layout_constraintTop_toTopOf="parent" />

To implement the functionality where certain domains are whitelisted and, when accessed within the consent platform (CMP) WebView, are not opened in an external browser like Chrome but within the WebView itself, you can implement a callback mechanism to perform custom actions based on the domain, such as opening an Android activity.

// apply the domains to be whitelisted
CmpConfig.apply {
            id = cmpId
            domain = cmpDomain
            appName = cmpAppName
            language = cmpLanguage
            domainWhitelist = cmpDomainWhitelist
        }


// implement the callback: CmpOnClickLinkCallback
    override fun onClickLink(url: String): Boolean {
        Log.d("CMP", url)
        // Business logic
        return true // return handleWebViewInteraction boolean
    }

Using the SDK

In order to check whether a vendor or purpose have consent, you can use the two methods:

cmpManager?.hasPurposeConsent(purposeTextState.value)
cmpManager?.hasVendorConsent(vendorTextState.value)                             

Both methods hasPurposeConsent and hasVendorConsent require two parameter:

  • id - String of the vendor or purpose ID. Please note that vendor IDs can have different formats ("123", "s123" and "c123"), please double-check with Menu > Vendors and Menu > Purposes in your consentmanager account.
  • isIABVendor / isIABPurpose - If the vendor or purpose is a vendor/purpose that follows the IAB TCF standard, you will need to set a true, otherwise a false.

Remember: All vendor that do not belong to the IAB have IDs starting with a "s" or "c" (e.g. "s123"); vendors that belong to the IAB have IDs not starting with a "s" or "c".

Re-Opening the Consent Screen

In order to allow the user to change the choices, you can simply call openCmpConsentToolView():

cmpManager?.openConsentLayer(context)

In some cases an native app might contain webviews in order to display certain things like advertising oder content. In order to transmit the consent information from the SDK to the webview, please use the function:

String consentData = cmpConsentTool?.exportCmpString();

This will export the consent information and all further data that is needed by the CMP. You can then pass this information to the CMP that is in your webview by adding it to the URL that is called in the webview:

myWebView.loadURL("https://mywebsite.com/....#cmpimport=" + consentData);

Custom Event Listeners

To add additional process logic you can make use of Event Listeners. Following Event Listeners are available:

Name

Occurrs

 

OnOpenCallback

Listener for Event when CMP opened

OnCMPCloseCallback

Listener for Event when CMP is closed

OnCMPNotOpenedCallback

Listener for Event when CMP doesn't need to be opened

OnErrorCallback

Listener for Event when there is an error in the consent management process.

OnButtonClickedCallback

Listener for ButtonEvent

Import/Export Consent

To import or export the consent you can use the function exportCMPData(Context context) and importCMPData(Context context, String cmpData). Check the example below: 

The consentString you need to pass should be base64 encoded.

 

CMP SDK Sequence Diagram

Cmp-Sequence-Diagram-(1).png


Logging

When using our Android SDK, you may need to debug or analyze log information for various purposes. The logs generated by our SDK are tagged with "CMP", which allows you to easily filter and view only the relevant logs. This guide provides step-by-step instructions on how to access these logs using Logcat in Android Studio.

Search for the Tag: In the search bar above the log statements, type CMP to filter out the logs tagged with "CMP".

Optional: Enable Debug Mode

In CMPConfig, set isDebugMode = true.

val config = CmpConfig.apply {
    // ... other settings
    isDebugMode = true
}
  • Enables more detailed logs tagged with "CMP".
  • Useful for debugging and analysis.

Troubleshooting

Class Not Found or NoSuchMethodException:

ProGuard can sometimes obfuscate class names or remove methods that are dynamically referenced via reflection. To fix this, you need to specify the classes and methods that should be kept intact in the ProGuard configuration file using the -keep directive.

Example ProGuard configuration to keep a specific class and its methods:

# Kotlin serialization looks up the generated serializer classes through a function on companion
# objects. The companions are looked up reflectively so we need to explicitly keep these functions.
-keepclasseswithmembers class **.*$Companion {
    kotlinx.serialization.KSerializer serializer(...);
}
# If a companion has the serializer function, keep the companion field on the original type so that
# the reflective lookup succeeds.
-if class **.*$Companion {
  kotlinx.serialization.KSerializer serializer(...);
}
-keepclassmembers class <1>.<2> {
  <1>.<2>$Companion Companion;
}

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

-keepattributes JavascriptInterface

-keepclassmembers class net.consentmanager.sdk.common.callbacks.* {
   public *;
}

-keepclassmembers class net.consentmanager.sdk.consentlayer.ui.consentLayer.CmpWebView {
   public *;
}

-keepclassmembers class net.consentmanager.sdk.consentlayer.ui.CmpLayerAppInterface {
   public *;
}
-keep class net.consentmanager.sdk.CMPConsentTool {
                                                      *;
                                                  }

-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

-keepattributes JavascriptInterface

# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`.
# If you have any, uncomment and replace classes with those containing named companion objects.
#-keepattributes InnerClasses # Needed for `getDeclaredClasses`.
#-if @kotlinx.serialization.Serializable class
#com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions.
#com.example.myapplication.HasNamedCompanion2
#{
#    static **$* *;
#}
#-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept.
#    static <1>$$serializer INSTANCE;
#}

 

Back to top