Introduction

The Cookie Information Mobile Consents SDK is a library that helps you to collect and manage consents for personal data processing from your users. It is available for iOS and Android.

On iOS it's compatible with Swift and Objective-C, can be installed using Swift Package Manager, CocoaPods, or manually. On Android it’s compatible with Kotlin and Java on Android, it can be installed from the Maven central repository or manually from Github.

Key Features:

Installation Options: It's easy to integrate into your app using common package managers. Manual installation is possible but not recommended due to the need for manual updates.

Easy Initialisation: You can start using the SDK by importing it and initialising it with a few key parameters like client ID, secret, and solution ID obtainable from the Cookie Information Consent Management Platform.

Built-In User Interface: The SDKs come with pre-built screens to manage user consents. They automatically use the app's current language for translations, defaulting to English if the app's language isn't available.

Privacy Pop-Up Customisation: Developers can customise the appearance and behaviour of the privacy pop-up. This includes setting the accent colour, fonts, and handling user interactions like accepting or rejecting consents.

Custom UI Option: For more flexibility, you can create a custom UI to manage consents while still utilising the SDK's data handling capabilities.

Error Handling: The SDK includes methods to handle errors that might occur during the consent process.

Local and Server Consent Management: Developers can easily send consent data to the server or retrieve locally saved consent data.

Logging and Debugging: The SDK can log network events to help with debugging.

Device Identifier Display: Each user's consents are linked to a unique device identifier, which is visible in the privacy policy section of the app.

This SDK simplifies the process of managing user consents in iOS apps, ensuring compliance with data privacy regulations while offering a degree of customisation to fit the app’s design.

How it works

The SDK provides a simple UI that you can use to collect consents from your users. It also provides an API that you can use to manage consents programmatically. The SDK stores the consents in a local database on the user's device and also transmits them to the Cookie Information Consent Engine for archival and auditing purposes. The local database is encrypted and can only be accessed by your app.

The SDK also provides a UI that allows your users to view and manage their consents.

Requirements

Our SDKs work natively with iOS and Android operating systems, and they are compatible with the most popular cross-platform application development frameworks*.

Android

iOS

The Cookie Information Mobile Consents SDK for iOS supports iOS projects based on Swift or Objective-C.

As of SDK version 1.5.0 the following requirements need to be met:

  • iOS 11.0 or later
  • Swift or Objective-C
  • or cross-platform or hybrid technologies see the compatibility table below* s of version 1 the iOS SDK supports iOS versio

* unless the cross-platform frameworks is specifically mentioned to be supported it may require additional code - a so called wrapper - to be used in said framework.

Setup

Obtaining the API credentials

In order to use the Cookie Information Mobile Consents SDKs you need to have the following credentials:

  • Client ID
  • Client Secret
  • Solution ID

You can read in detail about setting up your account and obtaining the credentials here

Android SDK

Maven Central

Installation

MobileConsentsSDK is available through Gradle, by adding te dependency to your project.. Kotlin DSL

implementation("com.cookieinformation:mobileconsents:<latest_release>")

Groovy

implementation 'com.cookieinformation:mobileconsents:<latest_release>' 

Initializing

Create an instance of the sdk, and initialize prior to accessing the sdk at any point. You can initialize with or without theming and styling (for theming and styling its required to have compose dependencies.) The SDK credentials can be fetched from the platform here: https://go.cookieinformation.com/login This SDK requires you to ensure the language used for the sdk, is fully set on the platform, and all data exists. So if you choose to use the sdk in German, please ensure all fields are set on the platform.

The recommended implementation would be having the sdk invoking (most likely) the showPrivacyPopUpIfNeeded, when needed, so just initialize prior to calling the method

The minimum required data for initializing the SDK would be the following:

    ConsentsUISDK.init(
        clientID = "<CLIENT_ID>",
        clientSecret = "<CLIENT_SECRET>",
        solutionId = "<SOLUTION ID>",
    )

Here is an example of all the arguments and data that support the SKD.

    ConsentsUISDK.init(
    clientID = "<CLIENT_ID>",
    clientSecret = "<CLIENT_SECRET>",
    solutionId = "<SOLUTION ID>",
    languageCode = "FR",//Can be null, in this case it will take the devices configured language. 
    typography = defaultTypography.copy(bodyMedium = TextStyle.Default),
    customDarkColorScheme = darkColorScheme(
        primary = Color.Yellow,
        secondary = Color.Green,
        tertiary = Color.Black
    ),
    customLightColorScheme = lightColorScheme(
        primary = Color.Red,
        secondary = Color.Yellow,
        tertiary = Pink40
    ),
)

UI language

The language set for the sdk, will be the language used for all components, and will ignore the systems language. In case no language has been set, (in the init function), the sdk will use the devices configured language. Its important to note, it is the developers responsibility to ensure that any potential languages to be used are set on CookieInformation's platform.

Using built-in mobile consents UI

SDK contains built-in screens for managing consents. Please ensure you set the correct language code you expect the consents to use, and that has been fully set on the platform.

Consents Screen

Standard flows

Presenting the privacy pop-up

To show the Privacy Pop Up screen, whatever the state is use showPrivacyPopUp (typically used in settings to allow for modification of the consent) or to show the Privacy Pop Up screen in case the user has not consented to the latest version use showPrivacyPopUpIfNeeded (typically used at startup to present the privacy screen conditionally. See more below) method:

    ConsentsUISDK.showPrivacyPopup(callingActivity).collect {
        it.fold(
            onSuccess = {
                it.forEachIndexed { index, consentItem ->
                    Log.d("####", "onCreate: ${consentItem.title}  ${consentItem.accepted}")
                }
            },
            onFailure = { Log.d("####", it.message ?: "no message") }
        )
    }

The above function takes an optional completion block argument that should be used to react to the users consent and start or block various third-party SDKs.

Presenting the privacy pop-up conditionally

The showPrivacyPopUpIfNeeded method is typically used to present the popup after app start (or at a point the developer deems appropriate). The method checks if a valid consent is already saved locally on the device and also checks if there are any updates on the Cookie Information server. In case there is no consent saved or the consent version is different from the one available on the server, the popup will be presented, otherwise only the completion closure is called. Using the ignoreVersionChanges parameter allows the developer to turn off the version checking mechanism and ignore consent version changes coming from the server.

ConsentsUISDK.showPrivacyPopupIfNeeded(callingActivity).collect {
        it.fold(
            onSuccess = {
                it.forEachIndexed { index, consentItem ->
                    Log.d("####", "onCreate: ${consentItem.title}  ${consentItem.accepted}")
                }
            },
            onFailure = {
                Log.d("####", it.message ?: "no message")
            }

        )
    }

Tracking the changes of the accepted consents

ConsentsUISDK.getSavedItemsAsFlow().collect {
    //collects emitted Result<List<ConsentItem>> objects, so can track the changes
}

Managing multiple users

This SDK supports multiple users, if you would like to identify you users, and ask each user to consents, just pass the userId into the methods, showPrivacyPopUp etc. The argument userId is by default null which represents an anonymous user. Please note, user management is applicable per device, and not across multiple devices, so each user will need to interact on each device used.

Example for displaying for an anonymous user:

ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, null).collect { consents ->
    //returns the result for an anonymous user
}

Example for displaying for a user identified as "user_email":

ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, "user_email").collect { consents ->
    //returns the result for a user identified as user_email.
}

Handling errors

Both the showPrivacyPopUp and showPrivacyPopUpIfNeeded, return Flow<Result<List>>, so whenever any item is collected, you as a developer should handle the state according to your needs, see Kotlin.Result class for further information on the Result class here.

ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, userId).collect { consents ->
    if (consent.isSuccessful()) {
        consents.forEach { consent ->
            // handle user defined consent items such as age consent
            print("Consent given for: ${consentItem.title}  ${consentItem.accepted}")
        }
    } else { //failure.
        //handle error
    }
}

optional settings

Theming & Styling

The UI theme and font can be customized in the SDKs initializer, make sure you have Jetpack Compose dependencies in you project:

    ConsentsUISDK.init(
        clientID = "<CLIENT_ID>",
        clientSecret = "<CLIENT_SECRET>",
        solutionId = "<SOLUTION ID>",
        languageCode = "FR",
        typography = defaultTypography.copy(bodyMedium = TextStyle.Default),
        customDarkColorScheme = darkColorScheme(
            primary = Color.Yellow,
            secondary = Color.Green,
            tertiary = Color.Black
        ),
        customLightColorScheme = lightColorScheme(
            primary = Color.Red,
            secondary = Color.Yellow,
            tertiary = Pink40
        ),
)

Consent solution description and consent item texts can leverage HTML tags for basic text styling. Supported tags include:

  • <b> for bolding text
  • <i> and <em> for emphasizing text
  • <br> for line breaking
  • <ul> and <li> for creating lists
  • <a href> for embedding links

Displaying the device identifier

All consents sent to the Cookie Information servers are identified by a unique device identifier that is generated randomly after opening the privacy popup for the first time. This ID is necessary for Cookie Information to retrieve consents saved by the end user.

During normal operation the identifier is not required, however in case the end user wants to access their saved consents, it is only possible if they provide the above mentioned identifier. When using the default user interface, the device identifier can be located at the bottom of the privacy policy page (after tapping "read more"). It can be copied to the clipboard by tapping the text.

iOS examples

Installation in Xcode

Swift Package Manager

MobileConsentsSDK is available through the Swift Package Manager (SPM) and CocoaPods. For the best experience we recommend using SPM by adding a new Package Dependency to your XCode project with the following repository URL:

https://github.com/cookie-information/ios-release

Cocoapods

Add the following line to your Podfile and run pod install from your terminal.

  pod 'MobileConsentsSDK', :git => 'https://github.com/cookie-information/ios-release.git'

Manual installation

In you're unable to use SPM or CocoaPods in your project, you can add the source code to your project either as a Git submodule or manually copy it into your Xcode Workspace. Using the manual method is discouraged as it requires you to manually update the SDK when security or feature updates are released.

Initializing

Swift

import MobileConsentsSDK

let mobileConsentsSDK = MobileConsents(clientID: "<CLIENT_ID>",
                                                  clientSecret: "<CLIENT_SECRET>",
                                                  solutionId: "<SOLUTION ID>"
                                      )

Objective-C

@import MobileConsentsSDK;

MobileConsents *mobileConsents = [[MobileConsents alloc] initWithUiLanguageCode:@"EN"
                                                                clientID:@"<CLIENT_ID>"
                                                            clientSecret:@"<CLIENT_SECRET>"
                                                              solutionId:@"<SOLUTION ID>"
                                                             accentColor: UIColor.systemBlueColor
                                                                 fontSet: FontSet.standard
                                                                  enableNetworkLogger: YES];

Using built-in mobile consents UI

SDK contains built-in screens for managing consents. By default, built-in UI tries to use application's current langauge for consent translations. If application's language is not available in translations, English will be used.

Privacy Pop-Up

To show the Privacy Pop Up screen, use either showPrivacyPopUp (typically used in settings to allow for modification of the consent) or showPrivacyPopUpIfNeeded (typically used at startup to present the privacy screen conditionally. See more below) method:

mobileConsentsSDK.showPrivacyPopUp() { settings in
            settings.forEach { consent in
                switch consent.purpose {
                case .statistical: break
                case .functional: break
                case .marketing: break
                case .necessary: break
                case .custom:
                    if consent.purposeDescription.lowercased() == "age consent" {
                        // handle user defined consent items such as age consent
                    }
                    if consent.consentItem.id == "<UUID of consent item comes here>" {
                      // handle user defined consent items such as age consent based on UUID
                    }

                @unknown default:
                    break
                }
                print("Consent given for:\(consent.purpose): \(consent.isSelected)")
            }
        }

The above function takes an optional completion block argument that should be used to react to the users consent and start or block various third-party SDKs.

By default, the pop up is presented by top view controller of key window of the application. To change that, you can pass presenting view controller as an optional parameter.

Presenting the privacy pop-up conditionally

The showPrivacyPopUpIfNeeded method is typically used to present the popup after app start (or at a point the developer deems appropriate). The method checks if a valid consent is already saved on the device and also checks if there are any updates on the Cookie Information server. In case there is no consent saved or the consent version is different from the one available on the server, the popup will be presented, otherwise only the completion closure is called. Using the ignoreVersionChanges parameter allows the developer to turn off the version checking mechanism and ignore consent version changes coming from the server.

        mobileConsentsSDK.showPrivacyPopUpIfNeeded(ignoreVersionChanges: true) { settings in
         // handle results here
        }

Objective-C

Just like in Swift, the same methods are used to display the privacy pop-up, only with a slight variation to reflect Objective-C naming conventions.

       [self.mobileConsents showPrivacyPopUpIfNeededOnViewController:self
                                                         animated:YES
                                             ignoreVersionChanges:NO
                                                       completion:^(NSArray<UserConsent *> * _Nonnull) {
        // Handle consents here
    }];

Handling errors

Both the showPrivacyPopUp and showPrivacyPopUpIfNeeded can be passed a errorHandler closure that is called when an error occurs. After the errorHandler is called, the popup is dismissed by the router, the selection made by the user is persisted locally and an attempt is made the next time showPrivacyPopUpIfNeeded is called or if synchronizeIfNeeded method is called manually.

        mobileConsentsSDK.showPrivacyPopUpIfNeeded(ignoreVersionChanges: true) { settings in
         // handle results here
        } errorHandler: { err in
            // handle the error here
        }

Styling

The UI accent color and the fonts can be customized in the SDKs initializer:

MobileConsents( clientID: "<CLIENT_ID>",
                clientSecret: "<CLIENT_SECRET>",
                solutionId: "<SOLUTION ID>"
                accentColor: .systemGreen,
                fontSet: FontSet(largeTitle: .boldSystemFont(ofSize: 34),
                                  body: .monospacedSystemFont(ofSize: 14, weight: .regular),
                                  bold: .monospacedSystemFont(ofSize: 14, weight: .bold))
                                                                )

Consent solution description and consent item texts can leverage HTML tags for basic text styling. Supported tags include:

  • <b> for bolding text
  • <i> and <em> for emphasizing text
  • <br> for line breaking
  • <ul> and <li> for creating lists
  • <a href> for embeding links

Basic inline css are also supported, e.g. <span style=\"color:red\">Text with custom color</span>

UI language

By default, Privacy Pop-up and Privacy Center use application's current langauge for consent translations. If application's language is not available in consent translations, English is used.

You can override langauge used by the screens by initializing SDK with custom langauge code. See the example app for more details.

Building your custom UI

In case the built-in popup screen is too limiting for you, you can choose to build your own custom screen, while still using the data and communication built into the SDK.

To start you need to create a new class inheriting from UIViewController and conforming to PrivacyPopupProtocol. This protocol requires that you implement an initializer that takes a viewModel argument. This viewModel is passed in by the SDK and contains the data and methods necessary to display and save consents.

After setting up your UI components and constraints you should set up the viewModel callback functions:

  • onDataLoaded: ((PrivacyPopUpData) -> Void)? - which allows you to receive the data and configure the UI components. It is useful to keep a reference to the viewModel, because it contains functions to modify the state of the consent (consent given, or revoked), to save the consent, reject optional, or accept selection.
  • onError: ((ErrorAlertModel) -> Void)? - to receive notifications about errors
  • onLoadingChange: ((Bool) -> Void)? - to receive notifications about changes in the loading state (useful if you're using a spinner or similar progress indicator)
private func setupViewModel() {
  viewModel.onDataLoaded = { [weak self] data in
    guard let self = self else { return }
    self.titleLabel.text = data.title
    self.data = data
    self.table.reloadData()
  }
  viewModel.viewDidLoad()
}

To allow for the user to interact with the consent screen you'll need buttons that accept or reject the data collection/processing categories. In order to do so you'll need to create the buttons and make them call viewModel.acceptAll, viewModel.acceptSelected or viewModel.rejectAll.

Once you're ready with the view controller, you should use the showPrivacyPopUp or showPrivacyPopUpIfNeeded methods with the customViewType argument:

mobileConsentsSDK.showPrivacyPopUp(customViewType: CustomController.self) { settings in
  settings.forEach { consent in
    switch consent.purpose {
    case .statistical: break
    case .functional: break
    case .marketing: break
    case .necessary: break
    case .custom:
    if consent.purposeDescription.lowercased() == "age consent" {
    // handle user defined consent items such as age consent based on the name
    }
    if consent.consentItem.id == "<UUID of consent item comes here>" {
    // handle user defined consent items such as age consent based on UUID
    }
   } 
 }
}

To see a more complete implementation, please refer to the Example app and look for CustomPopup.swift

If you want to send consent to the server, first you have to create Consent object which structure looks like this:

var consent = Consent(consentSolutionId: "consentSolution.id", consentSolutionVersionId: "consentSolution.versionId")

/* if you want your consent to have a custom data you can add it as a last parametr */
let customData = ["email": "test@test.com", "device_id": "test_device_id"]
var consent = Consent(consentSolutionId: "consentSolution.id", consentSolutionVersionId: "consentSolution.versionId" customData: customData)

Then you have to add processing purposes which contains a given consents

/* given consents are included in main consent object as ProcessingPurpose objects which you can add to Consent object using `addProcessingPurpose` function */

let purpose = ProcessingPurpose(consentItemId: "consentItem.id", consentGiven: {true / false}, language: "en")
consent.addProcessingPurpose(purpose)

After setting up the Consent object you are ready to send it to the server

mobileConsentsSDK.postConsent(consent) { error in
  /* if error is nil it means that post succeeded */
}

Getting locally saved consents data

let savedData:[SavedConsent] = mobileConsentsSDK.getSavedConsents()

SavedConsent object structure

struct  SavedConsent {
  let  consentItemId: String
  let  consentGiven: Bool
}

Canceling last post to server request

mobileConsentsSDK.cancel()

Logging

The SDK can be configured to print the network events in the console. These events include all network requests, responses and errors. By default this option is disabled to keep the unnecessary clutter out of the console, however in case of unexpected behaviour or to verify that everything works as expected it can be switched on in the SDK initializer.

import MobileConsentsSDK

let mobileConsentsSDK = MobileConsents(clientID: "<CLIENT_ID>",
clientSecret: "<CLIENT_SECRET>",
solutionId: "<SOLUTION ID>",
enableNetworkLogger: true
)

Displaying the device identifier

All consents sent to the Cookie Information servers are identified by a unique device identifier that is generated randomly after opening the privacy popup for the first time. This ID is necessary for Cookie Information to retrieve consents saved by the end user.

During normal operation the identifier is not required, however in case the end user wants to access their saved consents, it is only possible if they provide the above mentioned identifier. When using the default user interface, the device identifier can be located at the bottom of the privacy policy page (after tapping "read more"). It can be copied to the clipboard by tapping the text and selecting the appropriate button from the action sheet.

Google Consent Mode

Introduction

Google Consent Mode is a way to set the behaviour of the Firebase Analytics SDK by specifying the consent decisions of the user. This can be achieved by calling the setConsent method of the Firebase SDK with one of the consent types. Cookie Information's Mobile Consent Management platform allows you to effortlessly manage your users' consents ant update Firebase using Consent Mode to ensure compliance with regulations.

Consent Mode 2.0 supports the following consent types:

ad_user_data
ad_storage
ad_personalization
analytics_storage

Prerequisites

By default, no consent mode values are set. In order to comply with privacy regulations explicit consent is required before data collection is started. To prevent Firebase from collecting such information, you need to specify default values for the above mentioned consent types.

Android

To disable data collection and storage by default add the following XML AndroidManifest.xml

<meta-data android:name="google_analytics_default_allow_ad_user_data" 
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_personalization_signals" 
android:value="false" />
<meta-data android:name="google_analytics_default_allow_analytics_storage" 
android:value="false" />

iOS

To disable data collection and storage by default add the following key-value pairs to the Info.plist of your application.

<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE</key>
<false/>

It is cruitial to inform the Firebase SDK when the user changes their consent. To update consent values after an app has launched, call the setConsent method. The value set by the setConsent method overrides the default setting and persists across app executions. The value remains in that state until setConsent is called again, even if a user closes and reopens the app. setConsent only updates the parameters you specify.

Android

The setConsent method is used to update the consents in the Firebase SDK:

Firebase.analytics.setConsent {
  analyticsStorage(<consent status>)
  adStorage(<consent status>)
  adUserData(<consent status>)
  adPersonalization(<consent status>)
}

Using the Cookie Information Android SDK you can retrieve the latest user consents. The consent decisions are stored as Boolean, so they need to be mapped to ConsentStatus.GRANTED and ConsentStatus.DENIED to be used with Firebase.

lifecycleScope.launch {
  (applicationContext as App).sdk.getSavedConsentsWithType(object : CallListener<Map<UUID, ConsentWithType>> {
    override fun onSuccess(result: Map<UUID, ConsentWithType>) {
      val mapped = result.values.associate { it.type to it.consented }
      Firebase.analytics.setConsent {
        analyticsStorage(if(mapped[ConsentItem.Type.TypeStatistical] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
        adStorage(if(mapped[ConsentItem.Type.TypeMarketing] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
        adUserData(if(mapped[ConsentItem.Type.TypeMarketing] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
        adPersonalization(if(mapped[ConsentItem.Type.TypeFunctional] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
      }
    }

    override fun onFailure(error: IOException) {}
  })
}

See the previous chapters about more details on the SDK setup and implementation.

iOS

Similarly to Android, the consents are updated using the setConsent method. The following snippet demonstrates an optional extention that maps the Cookie Information consent status to the Firebase Analytics ConsentStatus type.


extention UserConsent {
    var consentStatus: ConsentStatus {
        return isSelected ? ConsentStatus.GRANTED : ConsentStatus.DENIED 
    }
}

mobileConsentsSDK.showPrivacyPopUp() { settings in
            settings.forEach { consent in
                switch consent.purpose {
                case .statistical: 
                    Analytics.setConsent(.analyticsStorage: consent.consentStatus
                case .functional: break
                case .marketing: break
                     Analytics.setConsent([
                     .adStorage: consent.consentStatus,
                     .adUserData: consent.consentStatus,
                     .adPersonalization: consent.consentStatus,
                    ])

                case .necessary: break

                @unknown default:
                    break
                }
                print("Consent given for:\(consent.purpose): \(consent.isSelected)")
            }

            Analytics.setConsent([
                .analyticsStorage: ,
                .adStorage: <consent status>,
                .adUserData: <consent status>,
                .adPersonalization: <consent status>,
])

        }

See the previous chapters about more details on the SDK setup and implementation.

Verify your setup

You can verify that your consent settings are working as intended by viewing the log messages for your app.

Android

Follow these steps:

Enable verbose logging on your device. In the Android Studio logcat, find the log message that starts with Setting consent. For example, Ad storage is enabled, you'll see the following log message:

Setting consent, ... AD_STORAGE=granted

iOS

You can verify that your consent settings are working as intended by viewing the Xcode debug console for your app.

Follow these steps:

Enable verbose logging on your device. In the Xcode debug console, look for:

ad_storage analytics_storage ad_user_data ad_personalization For example, if Ad storage are enabled, you'll see the following message:

ad_storage is granted.

References

For further information and more technical details please refer to the Google Consent Mode documentation for mobile apps.

Feedback

How to report a bug

If you find a bug in the SDK, please send us a report via GitHub Issues. Android bugs should be reported in the Android SDK repository, iOS bugs in the iOS SDK repository.

Feature requests

We appreciate your feedback and are always interested in new ideas for our SDKs. If you have a feature request, please email us at support@cookieinformation.com.

Contributing

If you want to contribute to the SDK, please create a GitHub Issue first and describe your idea. We will then discuss the idea with you and decide whether it is a good fit for the SDK. If it is, you can create a pull request with your changes.