Skip to content

Fix Android New Arch Issue#180

Open
sharifhh wants to merge 3 commits intoUsercentrics:masterfrom
sharifhh:patch-1
Open

Fix Android New Arch Issue#180
sharifhh wants to merge 3 commits intoUsercentrics:masterfrom
sharifhh:patch-1

Conversation

@sharifhh
Copy link

@sharifhh sharifhh commented Jan 21, 2026

User description

User description

Codegen generates Double for number, you can check here https://reactnative.dev/docs/appendix

right now your whole TurboModule doesn't work for functions that takes number primitive type.

PR Type

Bug fix

Description

  • Replace Int with Double for number parameters in TurboModule methods

  • Align with React Native codegen specification for number primitives

  • Fix compatibility with Android New Architecture

Diagram Walkthrough

flowchart LR
  A["RNUsercentricsModuleSpec"] -->|"Update parameter types"| B["Int to Double conversion"]
  B -->|"Affects methods"| C["setCMPId, acceptAll, denyAll, track, etc."]
  C -->|"Ensures compatibility"| D["React Native codegen spec"]
Loading

File Walkthrough

Relevant files
Bug fix
RNUsercentricsModuleSpec.kt
Convert Int parameters to Double in TurboModule spec         

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt

  • Changed parameter type from Int to Double in setCMPId method
  • Updated acceptAll, acceptAllForTCF, denyAll, denyAllForTCF methods to
    use Double for numeric parameters
  • Modified saveDecisions and saveDecisionsForTCF methods to accept
    Double instead of Int
  • Changed saveOptOutForCCPA and track methods to use Double for numeric
    parameters
+10/-10 

CodeAnt-AI Description

Fix numeric parameter handling so TurboModule methods work on Android New Architecture

What Changed

  • Numeric parameters for several public module methods were changed from integer to number so JS numbers are accepted; affected methods include setCMPId, acceptAll, acceptAllForTCF, denyAll, denyAllForTCF, saveDecisions, saveDecisionsForTCF, saveOptOutForCCPA, and track
  • Incoming number values are converted to integers before calling the native implementation, preserving existing native behavior while accepting JS numeric types
  • Module specification was updated to match the React Native codegen expectation for number primitives so the TurboModule binds correctly on Android New Architecture

Impact

✅ Fewer native module failures on Android New Architecture
✅ Calls from JS with numeric arguments succeed for consent and tracking methods
✅ Consistent behavior for consent-related actions when invoked from React Native

💡 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:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

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:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

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.

@codeant-ai
Copy link

codeant-ai bot commented Jan 21, 2026

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 ·
Reddit ·
LinkedIn

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 21, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

Parameter types across nine ReactMethod signatures in the Usercentrics React Native module are converted from Int to Double. Implementation methods include corresponding .toInt() conversions before enum array index lookups to maintain semantic equivalence. No control flow or error handling changes are made.

Changes

Cohort / File(s) Summary
Module Interface Specification
android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt
Abstract method parameter types changed from Int to Double across nine methods: setCMPId, acceptAll, acceptAllForTCF, denyAll, denyAllForTCF, saveDecisions, saveDecisionsForTCF, saveOptOutForCCPA, track. Return types and method names unchanged.
Module Implementation
android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt
Implementation methods updated to match interface signatures. All enum index accesses converted with .toInt() calls: TCFDecisionUILayer.values()[fromLayer.toInt()], UsercentricsConsentType.values()[consentType.toInt()], UsercentricsAnalyticsEventType.values()[event.toInt()].

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

Review effort 2/5

Suggested reviewers

  • souzabrunoj
  • uc-brunosouza

Poem

🐰 Double the precision, halves the bytes?
No wait—we shrink it back with .toInt() rites!
Parameter types now float on high,
Till enums call them back to earth nearby. 🌱

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix Android New Arch Issue' is vague and generic, using non-specific language ('Issue') that doesn't clearly convey the actual change (parameter type conversion from Int to Double for TurboModule compatibility). Consider a more descriptive title like 'Change TurboModule numeric parameters from Int to Double for New Arch compatibility' to clearly communicate the nature of the fix.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai bot added the size:M This PR changes 30-99 lines, ignoring generated files label Jan 21, 2026
@pantoaibot
Copy link

pantoaibot bot commented Jan 21, 2026

PR Summary:

Update RN Usercentrics module spec to use Double for numeric params to fix React Native New Architecture (codegen/TurboModule) type mismatches.

Changes:

  • File modified: android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt
  • Replaced Int parameters with Double for methods exposed to JS:
    • setCMPId(id)
    • acceptAll(consentType)
    • acceptAllForTCF(fromLayer, consentType)
    • denyAll(consentType)
    • denyAllForTCF(fromLayer, consentType, unsavedPurposeLIDecisions)
    • saveDecisions(decisions, consentType)
    • saveDecisionsForTCF(tcfDecisions, fromLayer, saveDecisions, consentType, promise)
    • saveOptOutForCCPA(isOptedOut, consentType)
    • track(event)
  • No changes to method names, return types, or promise usage.
  • Purpose: avoid runtime/class-cast errors under RN New Architecture where JS numbers are treated as Double by codegen.

Impact:

  • Compatibility fix for TurboModules / new RN codegen; rebuild required. No functional or behavioral logic changes.

Reviewed by Panto AI

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 21, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Cast and validate Double to Int

In the implementation of acceptAll, convert the consentType from Double to Int
and validate that it is a whole number to avoid precision issues.

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt [67]

-abstract fun acceptAll(consentType: Double, promise: Promise)
+override fun acceptAll(consentType: Double, promise: Promise) {
+    val typeInt = consentType.toInt().takeIf { it.toDouble() == consentType }
+        ?: return promise.reject("INVALID_ARGUMENT", "consentType must be an integer")
+    core.acceptAll(typeInt, promise)
+}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential issue where fractional Double values from JavaScript could cause problems when an Int is expected, and it proposes a robust validation and conversion strategy for the implementation class.

Medium
  • Update

@codeant-ai
Copy link

codeant-ai bot commented Jan 21, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Enum index bounds
    Several methods convert incoming Double parameters to Int and use them to index enum arrays (e.g. TCFDecisionUILayer.values()[index], UsercentricsConsentType.values()[index], UsercentricsAnalyticsEventType.values()[index]) without validating the resulting index. If the JS layer sends an out-of-range number, negative value, NaN or Infinity, this will throw IndexOutOfBoundsException or produce unexpected behaviour. Caller input should be validated and handled gracefully.

  • Non-finite Double handling
    Double inputs may be NaN or infinite. Calling .toInt() on such values yields surprising results. Inputs should be checked with isFinite() (or isNaN()/isInfinite()) and handled (reject promise or use fallback).

  • Precision & range checks
    JavaScript numbers are doubles and can contain fractional values or values outside Int range. Methods that interpret these numbers as enum IDs or indexes (e.g. consentType, fromLayer, event) must validate that values are finite integers and within expected bounds before converting to Int to avoid subtle bugs or overflow.

  • Truncation / rounding semantics
    Converting Double to Int via toInt() truncates toward zero. If JS can send non-integer numbers (e.g. 1.9) this silently changes meaning. Decide whether values should be rounded, floored, or rejected and apply consistent conversion. This affects setCMPId, track and all enum-indexing usages.

  • Required runtime conversion
    The spec signatures were changed from Int to Double. Any existing module implementation that previously accepted Int must now convert Double to the integer types the underlying SDK expects. Ensure all implementations cast safely (with validation) and update call sites to avoid ClassCast or logic errors.

@pantoaibot
Copy link

pantoaibot bot commented Jan 21, 2026

Reviewed up to commit:90a4c939250d3e4ddeac3d88392464511c21a8d1

Additional Suggestion
Others - Introduce a single helper utility (e.g. NumberUtils or BridgeConverters) that centralizes conversions from Double -> Int and Double -> Enum (with bounds checks). Many methods require the same conversions (consentType, fromLayer, event, cmpId). Centralizing avoids duplication and makes it easier to maintain behavior (rounding/truncation policy, error messages). Example helper signatures: - fun doubleToIntStrict(value: Double, fieldName: String): Int - fun doubleToEnumOrdinal>(value: Double, values: Array, fieldName: String): T Use these helpers in every bridge method instead of repeating conversion logic.
// New file: android/src/main/java/com/usercentrics/reactnative/util/BridgeConverters.kt

package com.usercentrics.reactnative.util

import com.facebook.react.bridge.Promise

internal object BridgeConverters {

    fun doubleToIntStrict(value: Double, fieldName: String, promise: Promise? = null): Int {
        if (!value.isFinite()) {
            val message = "Invalid $fieldName: value must be finite"
            promise?.reject(IllegalArgumentException(message))
            throw IllegalArgumentException(message)
        }

        val intValue = value.toInt()
        if (intValue.toDouble() != value) {
            val message = "Invalid $fieldName: $value is not an integer"
            promise?.reject(IllegalArgumentException(message))
            throw IllegalArgumentException(message)
        }

        return intValue
    }

    fun <T : Enum<T>> doubleToEnumOrdinal(
        value: Double,
        values: Array<T>,
        fieldName: String,
        promise: Promise? = null,
    ): T {
        val index = doubleToIntStrict(value, fieldName, promise)
        if (index !in values.indices) {
            val message = "Invalid $fieldName: index $index out of bounds [0, ${values.lastIndex}]"
            promise?.reject(IllegalArgumentException(message))
            throw IllegalArgumentException(message)
        }
        return values[index]
    }
}

// Usage example in RNUsercentricsModule.kt

@ReactMethod
override fun track(event: Double) {
    val eventType = BridgeConverters.doubleToEnumOrdinal(
        value = event,
        values = UsercentricsAnalyticsEventType.values(),
        fieldName = "event"
    )
    usercentricsProxy.track(eventType)
}
  • Add validation for incoming Double values before converting: check value.isFinite() and not NaN, then ensure it is within the expected integer range and an integer when applicable (or define explicit rounding). For enum ordinals (e.g. fromLayer, consentType, event) validate that the resulting Int is within values().indices and return/reject with a clear error if out of bounds. Example behavior: if value is fractional, either reject with an error indicating invalid parameter type or explicitly apply Math.floor/round with documentation. This prevents silent wrong enum mapping or ArrayIndexOutOfBounds exceptions at runtime.
// Example validation usage in RNUsercentricsModule.kt

@ReactMethod
override fun acceptAll(consentType: Double, promise: Promise) {
    try {
        val type = BridgeConverters.doubleToEnumOrdinal(
            value = consentType,
            values = UsercentricsConsentType.values(),
            fieldName = "consentType",
            promise = promise,
        )

        handleResult(promise) {
            usercentricsProxy.acceptAll(type)
        }
    } catch (_: IllegalArgumentException) {
        // Promise already rejected in converter
    }
}

@ReactMethod
override fun setCMPId(id: Double, promise: Promise) {
    try {
        val intId = BridgeConverters.doubleToIntStrict(id, "cmpId", promise)
        usercentricsProxy.setCMPId(intId)
        promise.resolve(null)
    } catch (_: IllegalArgumentException) {
        // Promise already rejected
    }
}

Reviewed by Panto AI

@codeant-ai
Copy link

codeant-ai bot commented Jan 21, 2026

CodeAnt AI finished reviewing your PR.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt`:
- Around line 206-208: The track method currently indexes
UsercentricsAnalyticsEventType.values() with event.toInt() which can throw
ArrayIndexOutOfBounds; update RNUsercentricsModule.track to validate the index
before using it (e.g., obtain vals = UsercentricsAnalyticsEventType.values(),
check eventIndex >= 0 && eventIndex < vals.size), and if out of range handle
gracefully (log via usercentricsProxy.instance or no-op/return) instead of
indexing directly into UsercentricsAnalyticsEventType.values().
- Around line 134-140: The acceptAllForTCF method currently indexes enums
directly with TCFDecisionUILayer.values()[fromLayer.toInt()] and
UsercentricsConsentType.values()[consentType.toInt()] which can throw
ArrayIndexOutOfBoundsException for invalid Double inputs; add defensive
validation or conversion helper(s) (e.g., getTCFDecisionUILayer(fromLayer:
Double) and getConsentType(consentType: Double)) that convert toInt(), check
index is within values().indices, and throw/return a clear error; wrap the enum
access in try-catch in acceptAllForTCF and call promise.reject(...) with a
descriptive message on failure, otherwise resolve as before.

@codeant-ai
Copy link

codeant-ai bot commented Feb 3, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@sharifhh
Copy link
Author

sharifhh commented Feb 3, 2026

@islameldesoky95 can you please check this? 🙏

@codeant-ai codeant-ai bot added size:M This PR changes 30-99 lines, ignoring generated files and removed size:M This PR changes 30-99 lines, ignoring generated files labels Feb 3, 2026
@codeant-ai
Copy link

codeant-ai bot commented Feb 3, 2026

CodeAnt AI Incremental review completed.

@mattlennon3
Copy link

Can confirm this works for me. Thanks!

Copy link
Collaborator

@islameldesoky95 islameldesoky95 left a comment

Choose a reason for hiding this comment

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

Thank you for bringing this to our attention, we will take a look and surely apply the needed fix to our upcoming releases.

@Ernestas-Zidokas
Copy link

Thank you for bringing this to our attention, we will take a look and surely apply the needed fix to our upcoming releases.

When is the next release planed? Android is blocked because of this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 1/5 size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants