Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
[Release Notes](https://docs.usercentrics.com/cmp_in_app_sdk/latest/about/history/)
### 2.27.0 – Jun 1, 2026
## Features
* **[PUR Compliance]** Implemented Mandatory Label and Hide Vendor Toggles on the second layer — purposes and special features absent from `publisherRestrictions`/`specialFeatures` maps are rendered as mandatory (pre-consented, non-interactive with a "Mandatory" label), and `showTogglesForVendors: false` hides toggles on the Vendors/DPS tab while keeping them on the Purposes tab. All logic is gated behind `enableConsentOrPay`; existing configurations are fully unaffected
* **[PUR Compliance]** Extended mandatory label and hide vendor toggles behaviour to Flutter, React Native, and Unity bridges
* **[Unity]** Exposed GDPR legal texts in `getCmpData`, enabling fully custom TCF UI builds

## Fixes
* **[Android — Accessibility]** Fixed TalkBack reading consent layer content with wrong language pronunciation (WCAG 3.1.2 Language of Parts)
* **[Android — Accessibility]** Added visible focus indicators to interactive elements in the consent layer (WCAG 2.4.7 Focus Visible)
* **[Android — Accessibility]** Action buttons now correctly announced as buttons by TalkBack (WCAG 4.1.2 Name, Role, Value)
* **[Android — Accessibility]** Accordion controls now announced as interactive buttons by TalkBack (WCAG 4.1.2 Name, Role, Value)
* **[Android — Accessibility]** External links in the consent layer now announced as links by TalkBack (WCAG 4.1.2 Name, Role, Value)
* **[Android — Accessibility]** Fixed TalkBack focus jumping unexpectedly after accordion expand/collapse (WCAG 3.2.1 On Focus)
* **[Android — Accessibility]** Consent history table now semantically exposed to screen readers (WCAG 1.3.1 Info and Relationships)
* **[Android — Accessibility]** History section heading now programmatically marked as a heading for TalkBack navigation (WCAG 1.3.1 Info and Relationships)
* **[Android]** Fixed button text losing center alignment when label wraps to multiple lines
* **[Android]** Fixed first layer being blocked on the preview page when consent was already stored
* **[iOS]** Fixed SPM UI package incompatibility with Xcode 26
* **[TV]** Fixed CMP initialization failing on Samsung TV 2018 with `AbortController is not defined`
* **[Unity]** Added `changeLanguage()` API to the Unity bridge

### 2.26.3 – May 14, 2026
## Fixes
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def usercentrics_version = "2.26.3"
def usercentrics_version = "2.27.0"

group 'com.usercentrics.sdk.flutter'
version usercentrics_version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ private fun TCF2Settings.serialize(): Any {
"changedPurposes" to changedPurposes?.serialize(),
"acmV2Enabled" to acmV2Enabled,
"selectedATPIds" to selectedATPIds,
"consentOrPay" to consentOrPay?.serialize()
"consentOrPay" to consentOrPay?.serialize(),
"mandatoryLabel" to mandatoryLabel
)
}

Expand Down
16 changes: 8 additions & 8 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ PODS:
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- PromisesObjC (2.4.0)
- Usercentrics (2.26.3)
- usercentrics_sdk (2.26.3):
- Usercentrics (2.27.0)
- usercentrics_sdk (2.27.0):
- Flutter
- UsercentricsUI (= 2.26.3)
- UsercentricsUI (2.26.3):
- Usercentrics (= 2.26.3)
- UsercentricsUI (= 2.27.0)
- UsercentricsUI (2.27.0):
- Usercentrics (= 2.27.0)
- webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
Expand Down Expand Up @@ -137,9 +137,9 @@ SPEC CHECKSUMS:
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
Usercentrics: 82516ec0af3d552dced169285731571b71d74fc2
usercentrics_sdk: c4758f2cc6eca0f410990a92e3b846adb9e5da48
UsercentricsUI: 085bb51480cdd35d1b8c0f4661c72fa728a163ba
Usercentrics: e980f9ab4cf1d1c6de5825d7c23ca8ada2d6f0a5
usercentrics_sdk: 8c1ae61a079ede9cbe1849cf575ac97500aef364
UsercentricsUI: 3297ec6fb0e2cbb781abf4e61377979099007982
webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2

PODFILE CHECKSUM: e97bfdbafeca8809c8aa9477153c465633bd1c02
Expand Down
10 changes: 5 additions & 5 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -196,17 +196,17 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.9"
usercentrics_sdk:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "2.26.2"
version: "2.27.0"
vector_math:
dependency: transitive
description:
Expand Down
3 changes: 2 additions & 1 deletion ios/Classes/Serializer/CMPDataSerializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ extension TCF2Settings {
"changedPurposes": self.changedPurposes?.serialize() as Any,
"acmV2Enabled" : self.acmV2Enabled,
"selectedATPIds" : self.selectedATPIds,
"consentOrPay": self.consentOrPay?.serialize() as Any
"consentOrPay": self.consentOrPay?.serialize() as Any,
"mandatoryLabel": self.mandatoryLabel
]
}
}
Expand Down
2 changes: 1 addition & 1 deletion ios/usercentrics_sdk.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'usercentrics_sdk'
s.version = '2.26.3'
s.version = '2.27.0'
s.summary = 'Usercentrics Flutter SDK.'
s.description = <<-DESC
Usercentrics Flutter SDK.
Expand Down
3 changes: 2 additions & 1 deletion lib/src/internal/serializer/tcf2_settings_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class TCF2SettingsSerializer {
acmV2Enabled: value['acmV2Enabled'] ?? false,
selectedATPIds: value['selectedATPIds']?.cast<int>() ?? [],
consentOrPay: TCF2ConsentOrPaySettingsSerializer.deserialize(
value['consentOrPay']));
value['consentOrPay']),
mandatoryLabel: value['mandatoryLabel'] ?? "Mandatory");
}
}

Expand Down
10 changes: 7 additions & 3 deletions lib/src/model/tcf2_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class TCF2Settings {
required this.changedPurposes,
required this.acmV2Enabled,
required this.selectedATPIds,
this.consentOrPay});
this.consentOrPay,
this.mandatoryLabel = "Mandatory"});

final String firstLayerTitle;
final String secondLayerTitle;
Expand Down Expand Up @@ -123,6 +124,7 @@ class TCF2Settings {
final bool acmV2Enabled;
final List<int> selectedATPIds;
final TCF2ConsentOrPaySettings? consentOrPay;
final String mandatoryLabel;

@override
bool operator ==(Object other) =>
Expand Down Expand Up @@ -192,7 +194,8 @@ class TCF2Settings {
changedPurposes == other.changedPurposes &&
acmV2Enabled == other.acmV2Enabled &&
listEquals(selectedATPIds, other.selectedATPIds) &&
consentOrPay == other.consentOrPay;
consentOrPay == other.consentOrPay &&
mandatoryLabel == other.mandatoryLabel;

@override
int get hashCode =>
Expand Down Expand Up @@ -255,7 +258,8 @@ class TCF2Settings {
changedPurposes.hashCode +
acmV2Enabled.hashCode +
selectedATPIds.hashCode +
consentOrPay.hashCode;
consentOrPay.hashCode +
mandatoryLabel.hashCode;

@override
String toString() => "$TCF2Settings($hashCode)";
Expand Down
16 changes: 8 additions & 8 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -380,26 +380,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
url: "https://pub.dev"
source: hosted
version: "1.30.0"
version: "1.29.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.9"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
url: "https://pub.dev"
source: hosted
version: "0.6.16"
version: "0.6.15"
typed_data:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repository: https://github.com/Usercentrics/flutter-sdk/
# [X] android/build.gradle
# [X] ios/usercentrics_sdk.podspec + pod install/update
# [X] CHANGELOG.md
version: 2.26.3
version: 2.27.0

environment:
sdk: ">=2.17.1 <4.0.0"
Expand Down
Loading