feat(MSDK-3172): Consume and expose DPS metadata in AppSDK#193
feat(MSDK-3172): Consume and expose DPS metadata in AppSDK#193uc-christiansousa wants to merge 1 commit intomasterfrom
Conversation
|
CodeAnt AI is reviewing your PR. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
📝 WalkthroughWalkthroughA new Changes
Sequence Diagram(s)sequenceDiagram
participant JS as JavaScript Client
participant RNBridge as React Native Bridge
participant NativeManager as Native Manager<br/>(iOS/Android)
participant Core as Usercentrics Core
JS->>RNBridge: getDpsMetadata(templateId)
activate RNBridge
RNBridge->>NativeManager: getDpsMetadata(templateId)
activate NativeManager
NativeManager->>Core: getDpsMetadata(templateId)
activate Core
Core-->>NativeManager: [metadata] or null
deactivate Core
NativeManager-->>RNBridge: [metadata] or null
deactivate NativeManager
RNBridge-->>JS: Promise<metadata | null>
deactivate RNBridge
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip You can customize the tone of the review comments and chat replies.Configure the |
Review Summary by QodoAdd getDpsMetadata method to consume and expose DPS metadata
WalkthroughsDescription• Add getDpsMetadata method to retrieve DPS metadata by template ID • Implement method across Android and iOS native modules • Add comprehensive unit tests for valid, null, and empty metadata cases • Expose method through TypeScript interfaces and Usercentrics SDK Diagramflowchart LR
A["Native Layer<br/>Android/iOS"] -->|getDpsMetadata| B["Manager Implementation<br/>UsercentricsManager"]
B -->|expose| C["React Native Module<br/>RNUsercentricsModule"]
C -->|bridge| D["TypeScript API<br/>Usercentrics.tsx"]
D -->|return| E["Metadata Dictionary<br/>Record or null"]
File Changes1. android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt
|
Code Review by Qodo
1. Metadata serialization loses fields
|
Sequence DiagramThis PR adds a new getDpsMetadata API to the App SDK and wires it end to end from JavaScript to the native Usercentrics core layer. The flow returns either a metadata object for a template id or null when no metadata is available. sequenceDiagram
participant App
participant UsercentricsAPI
participant NativeModule
participant UsercentricsCore
App->>UsercentricsAPI: Request DPS metadata with template id
UsercentricsAPI->>NativeModule: Ensure ready and call getDpsMetadata
NativeModule->>UsercentricsCore: Fetch DPS metadata for template id
UsercentricsCore-->>NativeModule: Metadata map or null
alt Metadata found
NativeModule-->>UsercentricsAPI: Resolve metadata object
else No metadata
NativeModule-->>UsercentricsAPI: Resolve null
end
UsercentricsAPI-->>App: Return DPS metadata result
Generated by CodeAnt AI |
|
PR Summary: Add support to retrieve DPS (data processor) metadata by templateId from native SDKs and expose it through the React Native bridge and TypeScript API.
|
| @ReactMethod | ||
| override fun getDpsMetadata(templateId: String, promise: Promise) { | ||
| val metadata = usercentricsProxy.instance.getDpsMetadata(templateId) | ||
| if (metadata == null) { | ||
| promise.resolve(null) | ||
| } else { | ||
| promise.resolve(metadata.toWritableMap()) | ||
| } | ||
| } |
There was a problem hiding this comment.
[CRITICAL_BUG] Wrap the new getDpsMetadata implementation in a try/catch and reject the promise on failure. Converting native Maps to WritableMap (metadata.toWritableMap()) can throw if values are not directly serializable to the bridge. Example actionable fixes: (1) surround the conversion with try { ... } catch (e: Exception) { promise.reject(e) } or (2) defensively validate/normalize the map values before calling toWritableMap(). This prevents unhandled exceptions that would crash the bridge or leave the JS promise unresolved.
@ReactMethod
override fun getDpsMetadata(templateId: String, promise: Promise) {
try {
val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
if (metadata == null) {
promise.resolve(null)
} else {
promise.resolve(metadata.toWritableMap())
}
} catch (e: Exception) {
promise.reject("usercentrics_getDpsMetadata_error", e.message, e)
}
}| @objc func getDpsMetadata(_ templateId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { | ||
| let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) | ||
| resolve(metadata as NSDictionary?) | ||
| } |
There was a problem hiding this comment.
[CRITICAL_BUG] Avoid force/unsafe bridging when resolving the metadata. resolve(metadata as NSDictionary?) may crash or produce unexpected results if the dictionary contains values that aren't bridgeable to Objective-C. Convert safely, e.g. guard let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) else { resolve(nil); return } then create an NSDictionary via NSDictionary(dictionary: metadata) or use JSONSerialization to ensure bridgeable types. Also consider catching exceptions and rejecting with an error when conversion fails.
@objc func getDpsMetadata(_ templateId: String,
resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) -> Void {
guard let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) else {
resolve(nil)
return
}
// Ensure only bridgeable Foundation types are passed to React Native
if JSONSerialization.isValidJSONObject(metadata) {
resolve(metadata as NSDictionary)
} else {
// Fallback: attempt to sanitize via JSON round‑trip
do {
let data = try JSONSerialization.data(withJSONObject: metadata, options: [])
if let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
resolve(jsonObject as NSDictionary)
} else {
reject("usercentrics_reactNative_getDpsMetadata_error",
"Failed to serialize DPS metadata",
nil)
}
} catch {
reject("usercentrics_reactNative_getDpsMetadata_error",
"Failed to serialize DPS metadata: \(error.localizedDescription)",
error)
}
}
}| @ReactMethod | ||
| abstract fun getDpsMetadata(templateId: String, promise: Promise) | ||
|
|
There was a problem hiding this comment.
[REFACTORING] You added a new abstract method to the TurboModule spec. Make sure to run the native codegen/prepare steps so generated JNI and TurboModule bindings are updated accordingly (e.g. run the project prepare/script that triggers generate-codegen-jni or run yarn prepare). Without regenerating, native binding mismatches can cause runtime crashes or missing methods in the bridge.
| getGPPData(): Promise<GppData>; | ||
| getGPPString(): Promise<string | null>; | ||
| getABTestingVariant(): Promise<string>; | ||
| getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>; |
There was a problem hiding this comment.
[REFACTORING] Type mismatch/consistency: you added getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>. The fabric TurboModule spec uses Promise<Object | null>. Align the types across both files to a single, specific shape (prefer Record<string, unknown> | null) to keep type safety consistent and avoid confusion when consuming the API.
// src/fabric/NativeUsercentricsModule.ts
export interface Spec extends TurboModule {
// ...existing methods...
- getDpsMetadata(templateId: string): Promise<Object | null>;
+ getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
}| getGPPData(): Promise<Object>; | ||
| getGPPString(): Promise<string | null>; | ||
| getABTestingVariant(): Promise<string>; | ||
| getDpsMetadata(templateId: string): Promise<Object | null>; |
There was a problem hiding this comment.
[REFACTORING] Use a consistent, explicit type for the new method signature instead of generic Object. Change getDpsMetadata(templateId: string): Promise<Object | null> to use the same type as the JS spec (e.g. Promise<Record<string, unknown> | null>) so TS types match between the TurboModule spec and the public TS declaration.
// src/fabric/NativeUsercentricsModule.ts
export interface Spec extends TurboModule {
// ...
getABTestingVariant(): Promise<string>;
getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
// ...
}| setGPPConsent: jest.fn(), | ||
| track: jest.fn(), | ||
| reset: jest.fn(), | ||
| getDpsMetadata: jest.fn(), |
There was a problem hiding this comment.
[VALIDATION] You added getDpsMetadata to the NativeModules mock. The JS implementation awaits RNUsercentricsModule.isReady() before calling the method; please ensure RNUsercentricsModule.isReady is mocked to a resolved value (e.g. jest.fn().mockResolvedValue(undefined)) in tests that call getDpsMetadata so the await doesn't produce surprising behavior. Also, if your production code prefers TurboModuleRegistry.get over NativeModules, make sure tests mock the TurboModule path as well (or explicitly import the same module path your code uses).
// At top-level in src/__tests__/index.test.ts, after defining RNUsercentricsModule mock
beforeEach(() => {
RNUsercentricsModule.isReady.mockResolvedValue(undefined);
});
// Or, inside each DPS metadata test:
RNUsercentricsModule.isReady.mockResolvedValueOnce(undefined);
// Additionally, if your production code ever switches to TurboModuleRegistry:
jest.mock('../fabric/NativeUsercentricsModule', () => {
return {
__esModule: true,
default: {
isReady: jest.fn().mockResolvedValue(undefined),
getDpsMetadata: jest.fn(),
// ...other mocked methods as needed
},
};
});| getDpsMetadata: async (templateId: string): Promise<Record<string, unknown> | null> => { | ||
| await RNUsercentricsModule.isReady(); | ||
| return RNUsercentricsModule.getDpsMetadata(templateId); | ||
| }, |
There was a problem hiding this comment.
[REFACTORING] Public wrapper getDpsMetadata is added — ensure its returned runtime type is documented in public typings and that callers know it can be null. Also consider normalizing the returned value (e.g. return {} instead of null) only if that matches product requirements; otherwise keep current null semantics but document them.
// src/Usercentrics.tsx
export interface UsercentricsPublicAPI {
// ...existing methods
/**
* Returns DPS metadata for the given template.
*
* When metadata is available, a flat key/value object is returned.
* When no metadata exists for the given templateId, this resolves to `null`.
*/
getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
}
export const Usercentrics: UsercentricsPublicAPI = {
// ...existing methods
getDpsMetadata: async (
templateId: string,
): Promise<Record<string, unknown> | null> => {
await RNUsercentricsModule.isReady();
const metadata = await RNUsercentricsModule.getDpsMetadata(templateId);
// keep native null semantics; callers must handle `null`
return metadata;
},
};|
Reviewed up to commit:8c529d1bb006b4275633046aefe94f9d09c866c2 |
| override fun getDpsMetadata(templateId: String, promise: Promise) { | ||
| val metadata = usercentricsProxy.instance.getDpsMetadata(templateId) | ||
| if (metadata == null) { | ||
| promise.resolve(null) | ||
| } else { | ||
| promise.resolve(metadata.toWritableMap()) | ||
| } |
There was a problem hiding this comment.
1. Metadata serialization loses fields 🐞 Bug ✓ Correctness
Android getDpsMetadata resolves SDK metadata via Map.toWritableMap(), but that converter ignores nulls and unsupported Number types (e.g., Long/Float) and does unsafe nested-map casts, which can lead to missing metadata fields or runtime exceptions when DPS metadata contains non-Int/Double values.
Agent Prompt
### Issue description
`getDpsMetadata` converts the SDK-returned metadata with `Map<String, Any?>.toWritableMap()`.
That converter:
- does not write `null` values (it drops keys)
- does not support generic `Number` (only `Int`/`Double`), so values like `Long`/`Float` are dropped
- uses unsafe casts for nested maps (`value as Map<String, Any>`) which can throw at runtime
This can cause missing fields or bridge crashes for real-world DPS metadata.
### Issue Context
The repository already includes a robust dynamic serialization approach in `GppDataExtensions.kt` (handles `null`, `Number`, `Iterable`, arrays, and has safe key handling). DPS metadata is similarly dynamic and should use the same robustness.
### Fix Focus Areas
- android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt[88-96]
- android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-115]
- android/src/main/java/com/usercentrics/reactnative/extensions/GppDataExtensions.kt[17-46]
### Implementation notes
- Prefer extracting a shared `Any?.toWritableValue()` / `Map<*, *>.toWritableMap()` / `Iterable<*>.toWritableArray()` utility (based on `GppDataExtensions.kt`) and use it for DPS metadata.
- Ensure `null` values become `putNull` / `pushNull` rather than being dropped.
- Normalize `Number` similarly to `GppDataExtensions.normalizeNumber` to avoid losing integer-ness.
- Avoid unchecked casts for nested maps; convert keys via `key?.toString() ?: continue`.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
|
||
| getDpsMetadata: async (templateId: string): Promise<Record<string, unknown> | null> => { | ||
| await RNUsercentricsModule.isReady(); | ||
| return RNUsercentricsModule.getDpsMetadata(templateId); |
There was a problem hiding this comment.
Suggestion: This new call assumes getDpsMetadata always exists on the native module, but on iOS legacy bridge builds the method is not exported, so this will throw undefined is not a function at runtime. Guard the method before calling it and fail with a controlled error (or safe fallback) instead of invoking an undefined function. [possible bug]
Severity Level: Major ⚠️
- ❌ `Usercentrics.getDpsMetadata()` crashes on legacy iOS bridge.
- ⚠️ DPS metadata feature unavailable for legacy iOS consumers.
- ⚠️ Runtime failure occurs after successful `isReady()` call.| return RNUsercentricsModule.getDpsMetadata(templateId); | |
| if (typeof RNUsercentricsModule.getDpsMetadata !== 'function') { | |
| throw new Error('Usercentrics React Native SDK: getDpsMetadata is not available in this native build.'); | |
| } |
Steps of Reproduction ✅
1. Build iOS with legacy bridge (non-new-architecture); JS resolves module through
fallback at `src/Usercentrics.tsx:25` and `src/NativeUsercentrics.ts:74`
(`TurboModuleRegistry.get(...) || NativeModules.RNUsercentricsModule`).
2. Call exported API `Usercentrics.getDpsMetadata("template123")` (public export at
`src/index.tsx:1`, implementation at `src/Usercentrics.tsx:103-105`).
3. On iOS legacy bridge, `ios/RNUsercentricsModule.mm:10-118` defines exported methods via
`RCT_EXTERN_METHOD(...)`, and this file has no `getDpsMetadata` export entry.
4. Because legacy `NativeModules.RNUsercentricsModule` lacks that function, call site
`src/Usercentrics.tsx:105` invokes `undefined`, causing runtime `TypeError:
...getDpsMetadata is not a function`.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/Usercentrics.tsx
**Line:** 105:105
**Comment:**
*Possible Bug: This new call assumes `getDpsMetadata` always exists on the native module, but on iOS legacy bridge builds the method is not exported, so this will throw `undefined is not a function` at runtime. Guard the method before calling it and fail with a controlled error (or safe fallback) instead of invoking an undefined function.
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.|
CodeAnt AI finished reviewing your PR. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
example/ios/exampleTests/RNUsercentricsModuleTests.swift (1)
566-601: Add descriptive messages toXCTFailcalls.Static analysis flagged missing assertion messages. Adding descriptions helps identify which assertion failed when debugging test failures.
🔧 Proposed fix
func testGetDpsMetadataWithValidData() { fakeUsercentrics.getDpsMetadataResponse = ["partner": "appsflyer", "source": "campaign_1"] module.getDpsMetadata("template123") { result in guard let result = result as? NSDictionary else { - XCTFail() + XCTFail("Expected NSDictionary result") return } XCTAssertEqual("appsflyer", result["partner"] as! String) XCTAssertEqual("campaign_1", result["source"] as! String) } reject: { _, _, _ in XCTFail("Should not go here") } XCTAssertEqual("template123", fakeUsercentrics.getDpsMetadataTemplateId) }func testGetDpsMetadataWithEmptyMap() { fakeUsercentrics.getDpsMetadataResponse = [:] module.getDpsMetadata("template123") { result in guard let result = result as? NSDictionary else { - XCTFail() + XCTFail("Expected NSDictionary result") return } XCTAssertEqual(0, result.count) } reject: { _, _, _ in XCTFail("Should not go here") } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example/ios/exampleTests/RNUsercentricsModuleTests.swift` around lines 566 - 601, Tests have XCTFail calls without descriptive messages which makes failures hard to diagnose; update the XCTFail usages in testGetDpsMetadataWithValidData, testGetDpsMetadataWhenNull, and testGetDpsMetadataWithEmptyMap to include clear descriptions (e.g., for reject closures use "Unexpected rejection in testGetDpsMetadataWithValidData/testGetDpsMetadataWhenNull/testGetDpsMetadataWithEmptyMap", and for guard failure use "Expected NSDictionary result in testGetDpsMetadataWithValidData"); ensure each XCTFail call across these functions includes a concise message identifying the test and failure reason.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt`:
- Around line 88-96: The getDpsMetadata ReactMethod references a non-existent
Usercentrics SDK method and will crash; either remove the entire getDpsMetadata
method from RNUsercentricsModule or replace its implementation by calling a
supported API (e.g., usercentricsProxy.instance.getCMPData() or
usercentricsProxy.instance.getConsents()) after confirming which API returns the
equivalent DPS metadata with Usercentrics support, then convert that result to a
WritableMap (using metadata.toWritableMap() or equivalent) and resolve the
promise; if you cannot confirm immediately, remove the method to prevent runtime
crashes and open a follow-up to reintroduce it once Usercentrics confirms the
correct API.
In `@sample/ios/sampleTests/RNUsercentricsModuleTests.swift`:
- Around line 570-572: Update the bare XCTFail() calls in
RNUsercentricsModuleTests.swift to include descriptive failure messages so
failures are actionable; specifically, modify the guard blocks that check "guard
let result = result as? NSDictionary else { XCTFail(); return }" (and the
similar guard at the other occurrence) to call XCTFail(...) with a short message
such as "expected 'result' to be NSDictionary but was nil or wrong type" or
test-specific context so the test output identifies what went wrong.
---
Nitpick comments:
In `@example/ios/exampleTests/RNUsercentricsModuleTests.swift`:
- Around line 566-601: Tests have XCTFail calls without descriptive messages
which makes failures hard to diagnose; update the XCTFail usages in
testGetDpsMetadataWithValidData, testGetDpsMetadataWhenNull, and
testGetDpsMetadataWithEmptyMap to include clear descriptions (e.g., for reject
closures use "Unexpected rejection in
testGetDpsMetadataWithValidData/testGetDpsMetadataWhenNull/testGetDpsMetadataWithEmptyMap",
and for guard failure use "Expected NSDictionary result in
testGetDpsMetadataWithValidData"); ensure each XCTFail call across these
functions includes a concise message identifying the test and failure reason.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c20c5ab4-9c6b-4591-bf9a-1596ddd9e455
📒 Files selected for processing (13)
android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.ktandroid/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.ktexample/ios/exampleTests/Fake/FakeUsercentricsManager.swiftexample/ios/exampleTests/RNUsercentricsModuleTests.swiftios/Manager/UsercentricsManager.swiftios/RNUsercentricsModule.swiftios/RNUsercentricsModuleSpec.hsample/ios/sampleTests/Fake/FakeUsercentricsManager.swiftsample/ios/sampleTests/RNUsercentricsModuleTests.swiftsrc/NativeUsercentrics.tssrc/Usercentrics.tsxsrc/__tests__/index.test.tssrc/fabric/NativeUsercentricsModule.ts
| @ReactMethod | ||
| override fun getDpsMetadata(templateId: String, promise: Promise) { | ||
| val metadata = usercentricsProxy.instance.getDpsMetadata(templateId) | ||
| if (metadata == null) { | ||
| promise.resolve(null) | ||
| } else { | ||
| promise.resolve(metadata.toWritableMap()) | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for any documentation or usage of getDpsMetadata in the codebase
rg -n "getDpsMetadata" --type-add 'kotlin:*.kt' --type kotlinRepository: Usercentrics/react-native-sdk
Length of output: 529
🏁 Script executed:
find . -name "build.gradle*" -type f | head -20Repository: Usercentrics/react-native-sdk
Length of output: 288
🏁 Script executed:
rg -n "usercentrics" --type-add 'gradle:*.gradle' --type gradle -i | head -30Repository: Usercentrics/react-native-sdk
Length of output: 1278
🏁 Script executed:
rg -n "2\.25\." --type-add 'gradle:*.gradle' --type gradleRepository: Usercentrics/react-native-sdk
Length of output: 138
🏁 Script executed:
cat -n android/build.gradle.kts | head -100Repository: Usercentrics/react-native-sdk
Length of output: 3728
🏁 Script executed:
rg -n "usercentrics-ui\|usercentrics_version" android/build.gradle.ktsRepository: Usercentrics/react-native-sdk
Length of output: 55
🏁 Script executed:
rg -n "usercentricsProxy" --type kotlinRepository: Usercentrics/react-native-sdk
Length of output: 20394
🏁 Script executed:
find . -name "UsercentricsProxy*" -type fRepository: Usercentrics/react-native-sdk
Length of output: 150
🏁 Script executed:
rg -n "interface UsercentricsProxy\|class.*UsercentricsProxy" --type kotlin -A 5Repository: Usercentrics/react-native-sdk
Length of output: 55
🏁 Script executed:
rg -n "getDpsMetadata" --type kotlin -B 2 -A 2Repository: Usercentrics/react-native-sdk
Length of output: 1292
🏁 Script executed:
cat -n android/src/main/java/com/usercentrics/reactnative/api/UsercentricsProxy.ktRepository: Usercentrics/react-native-sdk
Length of output: 2289
🏁 Script executed:
rg -n "getDpsMetadata" --type kotlin -B 5 -A 5Repository: Usercentrics/react-native-sdk
Length of output: 2599
🏁 Script executed:
find . -name "*Test*.kt" -type f -exec grep -l "getDpsMetadata" {} \;Repository: Usercentrics/react-native-sdk
Length of output: 55
🌐 Web query:
Usercentrics Android SDK 2.25.1 getDpsMetadata API changelog
💡 Result:
No specific changelog entry found for the getDpsMetadata API in Usercentrics Android SDK version 2.25.1. The release notes for 2.25.1 (released March 2, 2026) mention only "UI improvements and fixes" and "Patch with security fixes". No mention of getDpsMetadata or DPS-related API changes in 2.25.1, 2.25.0, or recent versions. Official API documentation lists methods like getCMPData, getConsents, but no getDpsMetadata. DPS (Data Processing Services) metadata is likely accessed via UsercentricsService.deviceStorage in getCMPData response, which received TCF Vendor Device Storage enhancements in 2.25.1 (new fields: sdks, specialPurposes, optOut in disclosures).
Citations:
- 1: https://pub.dev/packages/usercentrics_sdk/changelog
- 2: https://usercentrics.com/docs/apps/releases/
- 3: https://usercentrics.com/docs/apps/migration/tcf-device-storage-1-1/
- 4: https://docs.usercentrics.com/cmp_in_app_sdk/latest/api/usercentrics-core/
🌐 Web query:
Usercentrics SDK getDpsMetadata method documentation
💡 Result:
No official documentation for a "getDpsMetadata" method was found in Usercentrics SDKs across browser, mobile (iOS/Android/Flutter/Unity/React Native), or related APIs after extensive searches of official docs.usercentrics.com pages, pub.dev packages, and GitHub repos. Usercentrics SDKs provide similar functionality through methods like: - getServices or getServicesBaseInfo / getServicesFullInfo in browser SDK (returns Service[] with data processing service details) - getCMPData in Apps SDK Core API (includes services: [UsercentricsService]) - consents (Future<List>) in Flutter SDK "DPS" refers to Data Processing Services in Usercentrics terminology. If this is from a private/internal SDK version or custom wrapper, check your specific implementation or contact Usercentrics support. Primary docs: https://docs.usercentrics.com/
Citations:
- 1: https://docs.usercentrics.com/cmp_browser_sdk/
- 2: https://docs.usercentrics.com/cmp_browser_sdk/3.3.0/index.html
- 3: https://docs.usercentrics.com/cmp_in_app_sdk/latest/api/usercentrics-core/
- 4: https://docs.usercentrics.com/cmp_browser_sdk/0.4.5/classes/usercentrics.html
- 5: https://docs.usercentrics.com/cmp_browser_sdk/0.4.5/index.html
- 6: https://pub.dev/packages/usercentrics_sdk
- 7: https://docs.usercentrics.com/cmp_browser_sdk/2.8.0/index.html
- 8: https://docs.usercentrics.com/cmp_in_app_sdk/latest/integration/intro-apply/
- 9: https://github.com/Usercentrics
- 10: https://docs.usercentrics.com/cmp_browser_sdk/1.13.0/classes/usercentrics.html
- 11: https://docs.usercentrics.com/cmp_browser_sdk/4.50.0/classes/default.html
- 12: https://pub.dev/documentation/usercentrics_manager/latest/
- 13: https://pub.dev/documentation/usercentrics_sdk/latest
- 14: https://pub.dev/documentation/usercentrics_sdk/latest/usercentrics_sdk/Usercentrics-class.html
Remove getDpsMetadata method or verify API existence with Usercentrics support.
The getDpsMetadata(templateId: String) method is not documented in the official Usercentrics Android SDK v2.25.1 API. Official documentation and recent changelogs (including 2.25.1 released March 2, 2026) do not list this method. Similar functionality appears to be accessed through getCMPData() or getConsents() instead. Calling this non-existent method at runtime will cause a crash. Verify with Usercentrics whether this API exists in v2.25.1 or if an alternative method should be used.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt`
around lines 88 - 96, The getDpsMetadata ReactMethod references a non-existent
Usercentrics SDK method and will crash; either remove the entire getDpsMetadata
method from RNUsercentricsModule or replace its implementation by calling a
supported API (e.g., usercentricsProxy.instance.getCMPData() or
usercentricsProxy.instance.getConsents()) after confirming which API returns the
equivalent DPS metadata with Usercentrics support, then convert that result to a
WritableMap (using metadata.toWritableMap() or equivalent) and resolve the
promise; if you cannot confirm immediately, remove the method to prevent runtime
crashes and open a follow-up to reintroduce it once Usercentrics confirms the
correct API.
| guard let result = result as? NSDictionary else { | ||
| XCTFail() | ||
| return |
There was a problem hiding this comment.
Add assertion messages to XCTFail() calls.
Two XCTFail() calls have no message, which hurts debugging clarity (also matches SwiftLint warning).
Suggested patch
- guard let result = result as? NSDictionary else {
- XCTFail()
+ guard let result = result as? NSDictionary else {
+ XCTFail("Expected NSDictionary result for non-empty DPS metadata")
return
}
@@
- guard let result = result as? NSDictionary else {
- XCTFail()
+ guard let result = result as? NSDictionary else {
+ XCTFail("Expected NSDictionary result for empty DPS metadata map")
return
}Also applies to: 594-596
🧰 Tools
🪛 SwiftLint (0.63.2)
[Warning] 571-571: An XCTFail call should include a description of the assertion
(xctfail_message)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@sample/ios/sampleTests/RNUsercentricsModuleTests.swift` around lines 570 -
572, Update the bare XCTFail() calls in RNUsercentricsModuleTests.swift to
include descriptive failure messages so failures are actionable; specifically,
modify the guard blocks that check "guard let result = result as? NSDictionary
else { XCTFail(); return }" (and the similar guard at the other occurrence) to
call XCTFail(...) with a short message such as "expected 'result' to be
NSDictionary but was nil or wrong type" or test-specific context so the test
output identifies what went wrong.
CI Feedback 🧐A test triggered by this PR failed. Here is an AI-generated analysis of the failure:
|
CodeAnt-AI Description
Expose DPS metadata retrieval by template ID to JavaScript
What Changed
Impact
✅ Retrieve DPS metadata by template ID✅ Null-safe metadata responses for missing templates✅ Tests verify metadata access and edge cases💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.
Summary by CodeRabbit
New Features
getDpsMetadata(templateId)method to retrieve metadata for a specified template ID. Returns metadata object or null if unavailable. Now available on iOS and Android platforms.