Skip to content
Closed
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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
[Release Notes](https://docs.usercentrics.com/cmp_in_app_sdk/latest/about/history/)
### 2.26.2 – Apr 15, 2026
## Improvements
* Improved SDK initialization logging
## Fixes
* **[Android]** Fixed consent banner ignoring "Popup" mode dashboard configuration and always showing fullscreen
* **[Android]** Fixed `shouldCollectConsent` always returning `true` after app relaunch on TCF configs
* **[Android]** Fixed window leak when activity finishes while consent banner is still showing
* **[Android]** Fixed ATP list updates that could lead to infinite banner resurfaces
* **[iOS]** Fixed SVG banner logo failing to load due to SVGKit parsing error
* **[iOS]** Fixed missing padding and misalignment between toggle and label in second layer
* **[iOS]** Fixed toggle dropdown arrow alignment
* **[iOS]** Fixed Swift Package Manager unable to resolve `usercentrics-spm-ui` package
* **[TCF]** Fixed Stack appearing duplicated under Special Purposes section with broken consent persistence
* Fixed "More" button custom colors not being applied in the first layer
* Fixed mediation consent logs not appearing when applying consent

### 2.26.1 – Apr 07, 2026
## Features
* Added support for US National (GPP) privacy framework
Expand Down
2 changes: 1 addition & 1 deletion android/build-legacy.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def usercentrics_version = "2.26.1"
def usercentrics_version = "2.26.2"
version usercentrics_version

buildscript {
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
val usercentricsVersion = "2.26.1"
val usercentricsVersion = "2.26.2"
val reactNativeVersion = "+"

fun BooleanProperty(name: String): Boolean {
Expand Down
2 changes: 2 additions & 0 deletions ios/Extensions/UsercentricsCMPData+Dict.swift
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ extension CustomizationColor {
"toggleDisabledBackground" : self.toggleDisabledBackground as Any,
"toggleDisabledIcon" : self.toggleDisabledIcon as Any,
"secondLayerTab" : self.secondLayerTab as Any,
"moreBtnBackground" : self.moreBtnBackground as Any,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The new customization color mapping is incomplete: ccpaButtonTextColor is now part of CustomizationColor (also added in the updated mock), but it is not serialized in this dictionary. This causes a schema mismatch where React Native receives an incomplete color payload and cannot access that field on iOS. [logic error]

Severity Level: Major ⚠️
- ⚠️ iOS getCMPData omits CustomizationColor.ccpaButtonTextColor property.
- ⚠️ React Native apps cannot theme CCPA button text color.
- ⚠️ iOS bridge diverges from underlying Usercentrics CustomizationColor model.
- ⚠️ Tests cannot assert ccpaButtonTextColor presence in settings payload.
Suggested change
"moreBtnBackground" : self.moreBtnBackground as Any,
"ccpaButtonTextColor" : self.ccpaButtonTextColor as Any,
Steps of Reproduction ✅
1. From JavaScript, call `Usercentrics.getCMPData()` as done in
`sample/src/screens/CustomUI.tsx:5-7`, which invokes the native iOS bridge to fetch CMP
data.

2. On iOS, this calls `RNUsercentricsModule.getCMPData` at
`ios/RNUsercentricsModule.swift:18-20`, which resolves
`usercentricsManager.getCMPData().toDictionary()` and returns the resulting NSDictionary
back to JS.

3. `UsercentricsManagerImplementation.getCMPData` at
`ios/Manager/UsercentricsManager.swift:88-89` returns
`UsercentricsCore.shared.getCMPData()`, which is converted via
`UsercentricsCMPData.toDictionary()` in
`ios/Extensions/UsercentricsCMPData+Dict.swift:4-13`. That method includes `"settings":
self.settings.toDictionary()`, where `UsercentricsSettings.toDictionary()` at
`ios/Extensions/UsercentricsCMPData+Dict.swift:17-51` serializes `"customization" :
self.customization?.toDictionary() as Any`.

4. `UsercentricsCustomization.toDictionary()` at
`ios/Extensions/UsercentricsCMPData+Dict.swift:243-252` serializes `"color" :
self.color?.toDictionary() as Any`, which calls `CustomizationColor.toDictionary()`
defined at `ios/Extensions/UsercentricsCMPData+Dict.swift:271-45`. This mapping includes
keys like `"primary"`, `"secondLayerTab"`, `"moreBtnBackground"`, and `"moreBtnText"`
(lines 273-44) but does not serialize any `"ccpaButtonTextColor"` key. However, the
`CustomizationColor` type in the SDK clearly has a `ccpaButtonTextColor` property, as
shown by the mock initializer in `sample/ios/sampleTests/Mock/CMPData+Mock.swift:58-67`
and `80-83`, where `CustomizationColor.mock()` sets `ccpaButtonTextColor:
"ccpaButtonTextColor"`. Because `CustomizationColor.toDictionary()` never includes this
field, the NSDictionary returned by `getCMPData()` to JavaScript lacks
`settings.customization.color.ccpaButtonTextColor`, so any React Native code attempting to
read `data.settings.customization.color.ccpaButtonTextColor` will always get `undefined`
despite the native SDK providing a value.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** ios/Extensions/UsercentricsCMPData+Dict.swift
**Line:** 292:292
**Comment:**
	*Logic Error: The new customization color mapping is incomplete: `ccpaButtonTextColor` is now part of `CustomizationColor` (also added in the updated mock), but it is not serialized in this dictionary. This causes a schema mismatch where React Native receives an incomplete color payload and cannot access that field on iOS.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

"moreBtnText" : self.moreBtnText as Any,
Comment on lines +292 to +293
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Ios/android color fields diverge 🐞 Bug ≡ Correctness

iOS now includes moreBtnBackground/moreBtnText in CustomizationColor.toDictionary(), but
Android’s CustomizationColor.serialize() still omits them, so the JS payload differs by platform
and “More” button colors will be unavailable on Android.
Agent Prompt
### Issue description
iOS now serializes `CustomizationColor.moreBtnBackground` and `CustomizationColor.moreBtnText` into the JS payload, but Android does not. This makes the React Native API platform-inconsistent and prevents Android apps from receiving the new “More” button color customization.

### Issue Context
The iOS side added two new keys in `CustomizationColor.toDictionary()`. Android’s corresponding `CustomizationColor.serialize()` should expose the same keys when present.

### Fix Focus Areas
- android/src/main/java/com/usercentrics/reactnative/extensions/UsercentricsCMPDataExtensions.kt[308-330]
- ios/Extensions/UsercentricsCMPData+Dict.swift[270-295]

### Expected change
Add `"moreBtnBackground"` and `"moreBtnText"` to the map returned by `CustomizationColor.serialize()` (reading from the SDK model fields), matching the iOS key names.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +292 to +293
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check field parity for CustomizationColor across Swift/TS/Kotlin surfaces
rg -n --type=swift --type=ts --type=kt \
  'moreBtnBackground|moreBtnText|tabsBorderColor|ccpaButtonColor|ccpaButtonTextColor'

Repository: Usercentrics/react-native-sdk

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Search for CustomizationColor field definitions and usage
# Fix: use proper file type flags and broader search

# First, check rg supported types
echo "=== Checking available Kotlin patterns ==="
rg -n 'moreBtnBackground|moreBtnText|tabsBorderColor|ccpaButtonColor|ccpaButtonTextColor' --max-count=30

echo ""
echo "=== Locate CustomizationColor definition ==="
rg -n 'class CustomizationColor|interface CustomizationColor' --type=swift --type=ts

Repository: Usercentrics/react-native-sdk

Length of output: 903


🏁 Script executed:

#!/bin/bash
# Check the referenced mock file location and content
echo "=== Verify mock file reference ==="
find . -name "CMPData+Mock.swift" -type f

echo ""
echo "=== Read referenced lines 509-511 from mock file ==="
if [ -f "sample/ios/sampleTests/Mock/CMPData+Mock.swift" ]; then
  sed -n '500,520p' "sample/ios/sampleTests/Mock/CMPData+Mock.swift"
fi

Repository: Usercentrics/react-native-sdk

Length of output: 1145


🏁 Script executed:

#!/bin/bash
# Search for where these color fields are defined/used in native bridge
echo "=== Find all color field definitions across Swift and TypeScript ==="
rg -n -A3 -B3 'ccpaButtonColor|tabsBorderColor' --type=swift --type=ts | head -100

Repository: Usercentrics/react-native-sdk

Length of output: 999


🏁 Script executed:

#!/bin/bash
# Read the complete UsercentricsCMPData+Dict.swift file to see the full toDictionary method
wc -l ios/Extensions/UsercentricsCMPData+Dict.swift

Repository: Usercentrics/react-native-sdk

Length of output: 122


🏁 Script executed:

#!/bin/bash
# Search for CustomizationColor extension in the target file
rg -n -B5 -A30 'extension CustomizationColor' ios/Extensions/UsercentricsCMPData+Dict.swift | head -150

Repository: Usercentrics/react-native-sdk

Length of output: 1614


🏁 Script executed:

#!/bin/bash
# Get broader context around lines 292-293 to see the method structure
sed -n '250,310p' ios/Extensions/UsercentricsCMPData+Dict.swift

Repository: Usercentrics/react-native-sdk

Length of output: 2073


🏁 Script executed:

#!/bin/bash
# Find CustomizationColor class definition
rg -n -B2 -A50 'class CustomizationColor' --type=swift | head -100

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Search for CustomizationColor definition without restricting to "class"
rg -n 'CustomizationColor' --type=swift | grep -E '(struct|class|var|let|func).*CustomizationColor' | head -20

Repository: Usercentrics/react-native-sdk

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Find where CustomizationColor is first declared/defined
rg -n '^(struct|class|protocol|typealias)\s+CustomizationColor' --type=swift

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

#!/bin/bash
# List files in ios directory that might contain model definitions
find ios -name "*.swift" -type f | head -30

Repository: Usercentrics/react-native-sdk

Length of output: 1037


🏁 Script executed:

#!/bin/bash
# Search entire repo for CustomizationColor definition
rg -n '(struct|class|interface|type)\s+CustomizationColor' | head -20

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Also check if it's a TypeScript/JavaScript type
rg -n 'CustomizationColor\s*[:=]' --type=ts --type=js | head -20

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Look for import statements for CustomizationColor in the extension file
grep -n 'import\|CustomizationColor' ios/Extensions/UsercentricsCMPData+Dict.swift | head -10

Repository: Usercentrics/react-native-sdk

Length of output: 149


Add missing color fields to CustomizationColor.toDictionary().

Lines 292–293 correctly add moreBtnBackground and moreBtnText, but the serializer is missing three other color fields that appear in the mock data: tabsBorderColor, ccpaButtonColor, and ccpaButtonTextColor (see sample/ios/sampleTests/Mock/CMPData+Mock.swift lines 509–511). Ensure the bridge contract is complete and consistent between mock and implementation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Extensions/UsercentricsCMPData`+Dict.swift around lines 292 - 293, The
CustomizationColor.toDictionary() serializer is missing three color keys present
in the mock (tabsBorderColor, ccpaButtonColor, ccpaButtonTextColor); update the
toDictionary() implementation in the CustomizationColor type to include these
three keys (tabsBorderColor, ccpaButtonColor, ccpaButtonTextColor) alongside the
existing moreBtnBackground and moreBtnText so the bridge contract matches the
mock data (ensure you use the same dictionary key names and map them from the
corresponding CustomizationColor properties).

Comment on lines +292 to +293
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Architect Review — HIGH

The new "More" button color fields (moreBtnBackground, moreBtnText) are only exposed in the iOS CMP data serialization, while the Android serializer (CustomizationColor.serialize in UsercentricsCMPDataExtensions.kt) still stops at secondLayerTab, breaking the otherwise platform-symmetric getCMPData contract for custom UI colors.

Suggestion: Update the Android CustomizationColor.serialize() implementation to include moreBtnBackground and moreBtnText (mirroring the iOS CustomizationColor.toDictionary()), so getCMPData returns a consistent customization color payload on both platforms.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** ios/Extensions/UsercentricsCMPData+Dict.swift
**Line:** 292:293
**Comment:**
	*HIGH: The new "More" button color fields (`moreBtnBackground`, `moreBtnText`) are only exposed in the iOS CMP data serialization, while the Android serializer (`CustomizationColor.serialize` in UsercentricsCMPDataExtensions.kt) still stops at `secondLayerTab`, breaking the otherwise platform-symmetric `getCMPData` contract for custom UI colors.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

]
}
}
Expand Down
Loading
Loading