For the complete documentation index, see llms.txt. This page is also available as Markdown.

Android — Versions

Cette page est maintenue en anglais — une seule source évite qu'une traduction dérive de la réalité du SDK à chaque release.

All notable changes to the Android SDK. Entries are newest first.

Sections follow the same headings throughout: Features for new or changed behaviour, Fixes for corrections, Requirements at the end. Breaking changes are called out in their own block at the top of the entry.

Maintainers: a new entry is dated on the day the version is actually published, not when it is written. An entry marked (unreleased) has not been tagged yet — see the release checklist.

Next release (unreleased)

Fixes

  • When the configuration could not be loaded, the consent screen says so. It showed the banner with the default theme and empty lists; it now shows a message and a Close button, like iOS. The back button closes it without reporting a close.

2.0.0 (2026-10-05)

Published on Maven Central, like 1.2.0. The version number moves to 2.0.0 on every channel at once, because the iOS SDK opens its CocoaPods channel with it.

Breaking changes

  • ConsentButtonStyle.CLOSE is removed from the consent UI's public ConsentButtonStyle enum. The "Close link" refusal style is now rendered as a link in the banner header, which left the value without a use.

  • scopeReminderOpensHostnames is removed from the consent UI's public ConsentUiState, which gains scopeReminderSegments and purposesText2Segments. The scope reminder now carries its links as segments, each opening its own target, instead of making the whole text one tap target. Unlike the data classes below, no overload keeps the previous constructor or copy of ConsentUiState.

  • Four public data classes gain a field: GoogleConsentState.adSignalsFromTcf, UserAction.page_view_id, Settings.sirdataRestrictions and Info.lastUpdate. Their previous constructor and copy signatures are kept as overloads, so source code is unaffected; code compiled against 1.2.0 that calls them with default arguments must be recompiled.

Features

  • The consent adapters forward each choice to Firebase Analytics, AppsFlyer, Adjust and Branch. Measured against the latest version of each SDK, none of the four received it correctly in 1.2.0, and nothing said so: the AppsFlyer and Branch adapters called APIs that have moved or do not exist, the Adjust adapter turned measurement off after an "Accept all", and in a minified release build the Firebase adapter sent nothing. A failing adapter is now logged under its name, on the SirDataCMP Logcat tag; only an absent SDK stays silent. See Sharing consent with vendor SDKs.

  • The SDK ships its R8 rules. A minified release build no longer fails on org.slf4j.impl.StaticLoggerBinder, and the adapters survive shrinking: the rules you added for the SDK can go.

  • "TCF/Google Consent Mode Interoperability" (consentModeFromTcf) behaves as on the web. The SDK writes IABTCF_EnableAdvertiserConsentMode = 1, ping and getTCData carry enableAdvertiserConsentMode: true, and Firebase Analytics receives analytics_storage only, so that it derives the three ad signals from the TC string. 1.2.0 sent those three as denied, whatever the user chose.

  • Publisher restrictions are applied. The consent UI no longer asks a partner for a purpose the publisher forbids it, the TC string and the IABTCF_PublisherRestrictions{ID} keys carry the restrictions, and the signals sent to Google through Firebase and AppsFlyer take them into account.

  • The Sirdata consent string carries the restrictions the configuration applies to Sirdata partners, and the version of the Sirdata list it was built from (it always said 1).

  • The three non-versioned lists (Global Vendor List, Sirdata list, Google Additional Consent providers) are requested with the visitor's country, when it is known, so the API can filter them.

  • The consent archive carries the country and the revision of the configuration that was displayed. Every hit carries a page_view_id, drawn once per initialize(), so the load, the clicks and the answer of one display share it.

  • The banner's refusal button follows the publisher's style as the web does. "Close link" puts the refusal label in the header, in place of the close cross (it was a discreet text button next to the other buttons); "Big button (secondary color)" is outlined like "Customize my choices" (it was a solid grey block); "Big button (main color)" looks exactly like "Accept all" (it was drawn at 70 % opacity). The manual re-opening shows a "Reject all" button whatever the refusal type and style, with the close cross at the top; it showed no refusal at all.

  • The publisher's text size scales the consent UI by the web's ratios, 12/13 and 14/13 for "small" and "large" (about ±7.7 %), instead of ±15 %.

  • The purposes and partners screens carry the links of their scope reminder, as on the web: the list of the sites the consent covers, and the Consent Framework site.

  • Outside the US screen, the close button that saves nothing reports its answer, response:close, along with its click, ui:close, as the web does; 1.2.0 sent the click alone. The US screen's close button still reports ccpa_response:close alone. Under the CNIL variant, where the close button saves the choice, nothing changes.

  • The system back button is reported like the close button that saves nothing (response:close and ui:close, or ccpa_response:close on the US screen). It already closed the banner, without any report.

  • isGdprApplies() and the in-app TCF API return context.gdprApplies as served by the API; the SDK no longer adds forceGdpr on top of it. The server already folds forceGdpr into that value, so what an integrator sees does not change.

Fixes

  • The SDK no longer fails to start on a configuration that serves publisher restrictions. The API serves restrictionType as a number, which 1.2.0 could not decode: initialize() failed and the CMP never loaded.

  • Toggling a stack records only the members the screen shows, and a purpose row records only the legal bases the served list asks for. Both could record a consent or a legitimate interest the user was never asked for.

  • Utils.buildAddtlConsent returns the string the SDK stores in IABTCF_AddtlConsent, prefixed 2~. It returned a 1~ string that no device ever stored.

  • In dark mode, a logo or watermark set to "no image" no longer displays the word NONE, and an empty dark-mode image falls back to the light-mode one, as on the web.

Requirements

  • Android API 23 (6.0) or higher, compileSdk 34, Kotlin 1.9.22 or higher; verified with Android Gradle Plugin 8.2.2 on JDK 17. See Setup — Android, step 1.

1.2.0 (2026-09-23)

First public release of the Android SDK. Earlier version numbers exist in the repository history but were never resolvable by an integrator: no artifact had been published under com.sirdata.cmp on Maven Central, so this entry is the starting point of the public history rather than a delta.

Breaking changes

  • Two public symbols are removed. Neither has ever been reachable from a published artifact — nothing had been published under com.sirdata.cmp — so this is announced for the record rather than as a migration:

    • TcStringEncoder.convertTcStringToGppString(tcString). It built a GPP string carrying the TCF section alone, which stopped being the production path when the SDK started emitting the US National section: the GPP string and IABGPP_GppSID are now assembled together from one section list. Reading IABGPP_HDR_GppString is the supported way to obtain it.

    • Context.isAskLaterCappingActive(store). A dead duplicate of the "ask later" capping rule, and it used a different window from the live one — context.cappingInHours instead of the fixed one hour. The rule the SDK actually applies is internal to the display cascade; call awaitConsentDisplayDecision() to ask whether the banner should be shown.

Features

  • The main-thread contract of initialize, shutdown and setCcpaOptOut is enforced rather than only documented. The three read and re-encode the consent state — jurisdiction, configuration and store — together and without a lock, so calling them from a background thread is a race. Off the main thread the SDK now logs the violation, naming the entry point; declare debugMode(true) on the configuration and it throws instead, so the fault surfaces in your own debug build rather than as a rare, silent race in production. debugMode has no other effect.

  • IAB TCF v2.2 in-app CMP API (registered CMP ID 92), IAB GPP and CCPA/USP support. All signals are written to SharedPreferences under the standard IAB keys, so compliant vendor SDKs read consent with no integration code.

  • Native Jetpack Compose consent UI: banner, purposes and partners screens, themed from the publisher configuration.

  • Display cascade ported from the web CMP — awaitConsentDisplayDecision() decides whether and how to present the UI, covering partial consent, capping windows and the cookie wall.

  • MANUAL_DISPLAY and APPLY_CHOICES workflows for re-opening the UI from a settings screen and for asking only what is left to decide.

  • Google Additional Consent string and Google Consent Mode state derived from TCF purposes, with consent adapters for automatic forwarding.

  • The consent UI does not list a partner for which the user has no decision to make — a partner with neither a consent nor a legitimate-interest toggle.

  • 50 languages — every locale the Sirdata API serves. BCP 47 tags are matched with their full label and case-insensitively, the way Locale.toLanguageTag() actually reports them, and nb-NO / nn-NO / fil-PH resolve to Norwegian and Filipino through an alias table.

  • Right-to-left languages render right-to-left. The consent UI sets its own layout direction from the banner's language instead of inheriting the host app's — LTR as explicitly as RTL, which is what closes the inheritance for the 48 left-to-right languages.

  • In the "apply choices" workflow, the refusal button is not rendered when the publisher set the no-consent button to NONE — that is, when they explicitly chose not to offer a refusal on the banner.

  • forceGdpr is the single supported way to override GDPR applicability. The overlapping setGdprApplies command was removed before this first release, so it never reached an integrator.

  • GPP US National (section 7) is emitted alongside the deprecated uspv1 section, and IABGPP_GppSID is built from the same section list as the string rather than derived from it — it used to be read back out of a Fibonacci-encoded header, which cannot work, so it never announced anything but 2.

  • The publisher configuration is now fetched from the cacheApiRoot host (choices.consentframework.com by default) rather than apiRoot (api.consentframework.com). Both hosts serve the same endpoint, and the two responses were compared key by key: 614 keys against 615, no differing value, the single extra key being the context.region that only choices can carry — it sits behind the CDN that resolves the visitor's country and US state, which the US National section needs. Integrators who pin hosts in a network allowlist, a proxy rule or a certificate-pinning configuration should confirm cacheApiRoot is reachable — the other two hosts are unchanged, and all three remain configurable.

  • getUspString() returns an empty string when no opt-out decision has been recorded. "1---" is not a neutral default: the US Privacy spec makes it an explicit assertion that the consumer falls outside a US Privacy jurisdiction. The sale opt-out itself is recorded under its own key, so a value fabricated by an earlier SDK version can never be mistaken for a decision the user made.

Fixes

  • ping reports the undetermined state until the publisher configuration is loaded, instead of a default determination the CMP had not computed.

  • The library declares its material-icons-core dependency explicitly. It used to arrive transitively through the Compose BOM's material3; apps resolving a newer material3 — which no longer carries the icons — crashed with NoClassDefFoundError on the purposes screen and on the manual-display close button.

  • The library declares the INTERNET and ACCESS_NETWORK_STATE permissions in its own manifest, so integrators get them through manifest merging. An app without INTERNET previously crashed on first launch instead of degrading.

  • removeEventListener accepts a boxed Long, which is what a Java caller passes naturally (Long.valueOf(id)). It previously fell through to the null branch and the listener was never removed.

  • ping and getTCData read the TCF policy version and GDPR applicability through the same storage reader, so the two commands can no longer report different values in the same session.

Requirements

  • Android API 23 (6.0) or higher, Kotlin 1.9.22 or higher.

Mis à jour

Ce contenu vous a-t-il été utile ?