Skip to content

fix: add logical to handle local image asset#192

Open
uc-brunosouza wants to merge 1 commit intomasterfrom
MSDK-2572/Programmatically-defined-logo-not-visible-on-iOS
Open

fix: add logical to handle local image asset#192
uc-brunosouza wants to merge 1 commit intomasterfrom
MSDK-2572/Programmatically-defined-logo-not-visible-on-iOS

Conversation

@uc-brunosouza
Copy link
Collaborator

@uc-brunosouza uc-brunosouza commented Mar 19, 2026

CodeAnt-AI Description

Load logo images from file paths, URLs, or asset names when provided in the logo dictionary

What Changed

  • When a logo dictionary includes a file path or URL, the image is loaded from that path/URL so programmatically-provided logos become visible on iOS
  • Falls back to loading an image by asset name if a path/URL is not provided or fails
  • Returns nil if no usable image source is present (avoids attempting to load an empty name)

Impact

✅ Programmatic logos load from app file paths
✅ Programmatic logos load from remote URLs
✅ Fewer invisible logos when providing a logo dictionary

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

Summary by CodeRabbit

  • New Features
    • Enhanced image loading to support multiple sources: file paths, HTTP/HTTPS URLs, and traditional named images, with automatic fallback handling for more flexible and robust logo display.

@uc-brunosouza uc-brunosouza self-assigned this Mar 19, 2026
@codeant-ai
Copy link

codeant-ai bot commented Mar 19, 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

Review Summary by Qodo

Support local image paths for programmatic logo assets on iOS

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add support for local file path logo assets in addition to named assets
• Implement image(fromLogoPath:) method to handle multiple path formats
• Support file://, absolute paths, HTTP/HTTPS URLs, and named image assets
• Improve robustness with empty string validation and fallback logic
Diagram
flowchart LR
  A["UIImage Dictionary"] --> B{"Has logoPath?"}
  B -->|Yes| C["Parse logoPath"]
  C --> D{"Path Type?"}
  D -->|file://| E["Load from file"]
  D -->|Absolute /| F["Load from file"]
  D -->|HTTP/HTTPS| G["Download from URL"]
  D -->|Named| H["Load named asset"]
  E --> I["Return UIImage"]
  F --> I
  G --> I
  H --> I
  B -->|No| J{"Has logoName?"}
  J -->|Yes| K["Load named asset"]
  J -->|No| L["Return nil"]
  K --> I
Loading

Grey Divider

File Changes

1. ios/Extensions/UIImage+UsercentricsLogoDict.swift 🐞 Bug fix +31/-6

Add local image path support for logo assets

• Refactored init(from:) to support both logoPath and logoName parameters with priority to
 logoPath
• Added new private method image(fromLogoPath:) to handle multiple path formats including file://,
 absolute paths, HTTP/HTTPS URLs, and named assets
• Improved validation with empty string checks and proper fallback logic
• Enhanced error handling with multiple path resolution strategies

ios/Extensions/UIImage+UsercentricsLogoDict.swift


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 19, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Main-thread image download 🐞 Bug ➹ Performance
Description
UIImage.image(fromLogoPath:) performs a synchronous Data(contentsOf:) fetch for http(s) paths,
and this logo parsing runs on DispatchQueue.main during showFirstLayer/showSecondLayer. A remote
logoPath will block the UI thread while downloading, potentially freezing the app and triggering
watchdog termination.
Code

ios/Extensions/UIImage+UsercentricsLogoDict.swift[R31-35]

+        else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
+                let url = URL(string: logoPath),
+                let data = try? Data(contentsOf: url),
+                let image = UIImage(data: data) {
+            return image
Evidence
The new helper performs a blocking network read (Data(contentsOf:)). That helper is invoked when
parsing BannerSettings/GeneralStyleSettings (logo), and BannerSettings(from:) is constructed
inside RNUsercentricsModule.queue.async where queue is explicitly DispatchQueue.main, so the
blocking read happens on the main thread.

ios/Extensions/UIImage+UsercentricsLogoDict.swift[23-36]
ios/Extensions/BannerSettings+Dict.swift[27-47]
ios/RNUsercentricsModule.swift[19-85]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`UIImage.image(fromLogoPath:)` uses `Data(contentsOf:)` for `http(s)` logo paths. Because `BannerSettings(from:)` is built on `DispatchQueue.main` in `RNUsercentricsModule.showFirstLayer/showSecondLayer`, a remote `logoPath` will synchronously block the main thread.

## Issue Context
- `RNUsercentricsModule.queue` is set to `DispatchQueue.main`, and `BannerSettings(from: dict)` is created inside `queue.async`.
- `BannerSettings` parsing calls `UIImage(from:)` for the logo.
- `UIImage(from:)` calls `image(fromLogoPath:)`, which includes an `http(s)` branch using synchronous `Data(contentsOf:)`.

## Fix Focus Areas
- ios/Extensions/UIImage+UsercentricsLogoDict.swift[31-36]
- ios/RNUsercentricsModule.swift[22-85]
- ios/Extensions/BannerSettings+Dict.swift[27-48]

## Suggested fix approach
- Do not perform any network I/O inside `UIImage` initializers.
- Either:
 1) Remove the `http(s)` branch entirely (treat remote URLs as unsupported for `logoPath`), and rely on a separate async loader elsewhere, or
 2) Redesign the logo-loading flow to be asynchronous (e.g., pass `URL`/string through settings, fetch via `URLSession` off-main-thread, then update the banner UI when the image arrives).
- If you must keep remote support, ensure the fetch happens off the main thread and has timeouts/error handling, and avoid blocking the caller.

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



Remediation recommended

2. Fragile file URL handling 🐞 Bug ✓ Correctness
Description
For file:// logo paths, the code strips the scheme using string replacement and passes the result
to UIImage(contentsOfFile:). Since logoPath originates from React Native’s
ImageResolvedAssetSource.uri (a URI string), this parsing can fail for valid file URLs that
require proper URL-to-path conversion.
Code

ios/Extensions/UIImage+UsercentricsLogoDict.swift[R24-26]

+        if logoPath.hasPrefix("file://") {
+            let path = logoPath.replacingOccurrences(of: "file://", with: "")
+            if let image = UIImage(contentsOfFile: path) { return image }
Evidence
On the JS side, logoPath is set to ImageResolvedAssetSource.uri (a URI). On iOS, the
implementation treats that URI as a raw filesystem path by removing file:// via string replacement
instead of parsing it as a URL and using url.path, which is the correct way to convert file URLs
into filesystem paths.

src/models/BannerSettings.tsx[4-14]
ios/Extensions/UIImage+UsercentricsLogoDict.swift[23-30]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`image(fromLogoPath:)` currently converts `file://...` URIs into paths by doing a raw string replacement (`replacingOccurrences(of: "file://", with: "")`). Since `logoPath` is a URI string coming from React Native, it should be parsed as a `URL` and converted via `url.path`.

## Issue Context
- JS sets `logoPath` to `ImageResolvedAssetSource.uri`.
- iOS attempts to load the image from disk using `UIImage(contentsOfFile:)`, which requires a filesystem path.

## Fix Focus Areas
- ios/Extensions/UIImage+UsercentricsLogoDict.swift[23-30]
- src/models/BannerSettings.tsx[4-14]

## Suggested fix approach
- Replace the string manipulation with URL parsing, e.g.:
 - `if let url = URL(string: logoPath), url.isFileURL { return UIImage(contentsOfFile: url.path) }`
- Keep the existing absolute-path branch (`hasPrefix("/")`) as a fallback if needed.
- Avoid modifying the URI string manually; rely on `URL` to interpret and extract the path.

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

The UIImage convenience initializer now supports loading images via an optional logoPath field from a dictionary, with fallback to logoName. A new private helper method resolves logoPath strings across file://, absolute paths, HTTP/HTTPS URLs, and named resources.

Changes

Cohort / File(s) Summary
Logo Path Image Loading
ios/Extensions/UIImage+UsercentricsLogoDict.swift
Added support for optional logoPath dictionary field in initializer with priority over logoName. New private helper method image(fromLogoPath:) handles file://, absolute filesystem paths, HTTP/HTTPS URLs, and fallback to UIImage(named:).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A path through the files, both distant and near,
From web to the bundle, each image is clear!
With logos that load in all shapes and ways,
This rabbit hops happily through URL maze! 🎨✨

🚥 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 mentions 'handle local image asset' but the change adds broader support for multiple image sources including file:// paths, absolute filesystem paths, HTTP/HTTPS URLs, and fallback logic—not just local assets. Consider a more accurate title like 'fix: support loading images from multiple sources (logoPath)' or clarify what 'local image asset' specifically means in this context.
✅ 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
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MSDK-2572/Programmatically-defined-logo-not-visible-on-iOS
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

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

codeant-ai bot commented Mar 19, 2026

Sequence Diagram

This PR updates image creation to handle logoPath before logoName, enabling local file and remote path loading for logo assets. It preserves named asset lookup as a fallback when a valid path-based image is not available.

sequenceDiagram
    participant Caller
    participant UIImageExtension
    participant FileSystem
    participant Network
    participant AssetCatalog

    Caller->>UIImageExtension: Initialize image from logo dictionary
    UIImageExtension->>UIImageExtension: Check logoPath first

    alt logoPath is provided
        UIImageExtension->>FileSystem: Load image from local file path
        alt local file not available and path is remote
            UIImageExtension->>Network: Fetch image data from remote path
            Network-->>UIImageExtension: Return image data
        end
        UIImageExtension-->>Caller: Return image from logoPath
    else logoPath missing or invalid
        UIImageExtension->>AssetCatalog: Load image using logoName
        AssetCatalog-->>UIImageExtension: Return named asset image
        UIImageExtension-->>Caller: Return named image or nil
    end
Loading

Generated by CodeAnt AI

@pantoaibot
Copy link

pantoaibot bot commented Mar 19, 2026

PR Summary:

Adds support for loading a UIImage from a "logoPath" in addition to the existing "logoName", with multiple path handling (file://, absolute path, http(s)) and a fallback to named assets.

  • Rewrote UIImage.init?(from dictionary:) to:
    • Require only dictionary (no longer require logoName).
    • First try dictionary["logoPath"] (if non-empty) and create an image via a new helper.
    • If logoPath fails, fall back to dictionary["logoName"] via UIImage(named:).
    • Return nil if neither yields an image.
  • Added private static image(fromLogoPath:) that resolves:
    • file:// URIs and absolute file paths via UIImage(contentsOfFile:),
    • http:// or https:// via Data(contentsOf:) -> UIImage(data:),
    • and finally attempts UIImage(named:) as a last resort.
  • Behavior changes / notes:
    • Previously the initializer required logoName; now logoPath is preferred when present.
    • Network loading is synchronous (Data(contentsOf:)) — can block the calling thread (risk on main thread).
    • The init path uses image.cgImage for creating self — images without a cgImage representation may not initialize via that branch.
  • No dependency updates.

Reviewed by Panto AI

@codeant-ai
Copy link

codeant-ai bot commented Mar 19, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Network blocking
    The code synchronously downloads remote images using Data(contentsOf:) which will block the calling thread (often the main thread). This can cause UI freezes, slow app launch, and can be abused to cause DoS-like behaviour. The fetch should be performed asynchronously and/or moved off the init path.

  • Synchronous disk I/O
    The initializer performs synchronous file reads via UIImage(contentsOfFile:) for both "file://" and absolute-path cases. Doing disk I/O synchronously in an initializer used on the main thread can block the UI and lead to poor responsiveness. Consider making file loading asynchronous or ensure callers run this off the main thread.

  • Asset fidelity & bundle lookup
    Converting to a CGImage and initializing with cgImage may not preserve some UIImage asset traits (symbol images, PDF vector assets, image assets with traits). Also using UIImage(named:) without specifying a bundle can fail to find images that live in other bundles. Verify that these cases behave as expected and consider using bundle-aware loading or alternative handling for symbol/PDF assets.

Comment on lines +31 to +36
else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
let url = URL(string: logoPath),
let data = try? Data(contentsOf: url),
let image = UIImage(data: data) {
return image
}
Copy link

Choose a reason for hiding this comment

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

[CRITICAL_BUG] The implementation performs a synchronous network fetch using Data(contentsOf:) (lines 31-36). This will block the calling thread (very likely the main thread) and can freeze the UI or cause the app to be terminated for unresponsiveness. Move remote image loading off the calling thread and make it asynchronous (URLSession dataTask or use an image-loading/caching library). Also avoid initiating network I/O from a synchronous convenience initializer — consider providing an asynchronous factory/completion-based API (e.g. loadImage(from:completion:)) or return a placeholder and fetch the remote image asynchronously.

private static func image(fromLogoPath logoPath: String) -> UIImage? {
    if logoPath.hasPrefix("file://") {
        let path = logoPath.replacingOccurrences(of: "file://", with: "")
        if let image = UIImage(contentsOfFile: path) { return image }
    } else if logoPath.hasPrefix("/") {
        if let image = UIImage(contentsOfFile: logoPath) { return image }
    } else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
              let url = URL(string: logoPath) {
        // Avoid blocking the caller here; return a placeholder instead and
        // let the caller load the remote image asynchronously.
        return UIImage(named: logoPath)
    }

    if let image = UIImage(named: logoPath) { return image }
    return nil
}

// Example async loader (outside the UIImage extension):
func loadLogo(from logoPath: String, completion: @escaping (UIImage?) -> Void) {
    if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
       let url = URL(string: logoPath) {
        URLSession.shared.dataTask(with: url) { data, _, _ in
            let image = data.flatMap { UIImage(data: $0) }
            DispatchQueue.main.async {
                completion(image)
            }
        }.resume()
    } else {
        completion(UIImage.image(fromLogoPath: logoPath))
    }
}

@pantoaibot
Copy link

pantoaibot bot commented Mar 19, 2026

Reviewed up to commit:c61f77d434d17b2275784c1fa1c7c88f7a7cfe4e

Additional Suggestion
ios/Extensions/UIImage+UsercentricsLogoDict.swift, line:8-12 You call Self.image(fromLogoPath:) -> image and then require image.cgImage to create self via self.init(cgImage:...). image.cgImage can be nil for vector/PDF/Symbol images or some image formats. Provide a safe fallback when cgImage is nil: render the UIImage into a bitmap context (UIGraphicsImageRenderer) and create a cgImage-backed UIImage, or initialize via image.pngData()/image.jpegData() with self.init(data:) if acceptable. This avoids silently failing to construct the UIImage when cgImage is absent (current code simply falls through to nil).
convenience init?(from dictionary: NSDictionary?) {
    guard let dictionary = dictionary else { return nil }

    if let logoPath = dictionary["logoPath"] as? String, !logoPath.isEmpty,
       let image = Self.image(fromLogoPath: logoPath) {

        if let cgImage = image.cgImage {
            self.init(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation)
            return
        }

        // Fallback for images without a cgImage (e.g. PDFs, symbol images)
        let rendererFormat = UIGraphicsImageRendererFormat.default()
        rendererFormat.scale = image.scale
        let renderer = UIGraphicsImageRenderer(size: image.size, format: rendererFormat)
        let rasterized = renderer.image { _ in
            image.draw(in: CGRect(origin: .zero, size: image.size))
        }
        if let cgImage = rasterized.cgImage {
            self.init(cgImage: cgImage, scale: rasterized.scale, orientation: rasterized.imageOrientation)
            return
        }
    }

    if let logoName = dictionary["logoName"] as? String, !logoName.isEmpty {
        self.init(named: logoName)
        return
    }

    return nil
}
ios/Extensions/UIImage+UsercentricsLogoDict.swift, line:8-17 Behavioral change risk: original code used only "logoName" and initialized via self.init(named:). New code prioritizes "logoPath" over "logoName" (lines 8-17). This can change runtime behavior for callers/tests that previously relied on logoName being used. Either preserve previous precedence, or add clear documentation and update unit tests (e.g. BannerSettingsDictTests) to assert the new precedence. Ensure parity with Android behavior (see android/src/... BannerSettingsExtensions.kt lines 18-54) to keep cross-platform consistency.
convenience init?(from dictionary: NSDictionary?) {
    guard let dictionary = dictionary else { return nil }

    // Preserve previous behavior: prefer logoName when both are present
    if let logoName = dictionary["logoName"] as? String, !logoName.isEmpty {
        self.init(named: logoName)
        return
    }

    if let logoPath = dictionary["logoPath"] as? String, !logoPath.isEmpty,
       let image = Self.image(fromLogoPath: logoPath) {
        if let cgImage = image.cgImage {
            self.init(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation)
            return
        }
        let renderer = UIGraphicsImageRenderer(size: image.size)
        let rasterized = renderer.image { _ in
            image.draw(in: CGRect(origin: .zero, size: image.size))
        }
        if let cgImage = rasterized.cgImage {
            self.init(cgImage: cgImage, scale: rasterized.scale, orientation: rasterized.imageOrientation)
            return
        }
    }

    return nil
}

Reviewed by Panto AI

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

🧹 Nitpick comments (3)
ios/Extensions/UIImage+UsercentricsLogoDict.swift (3)

28-30: Swift style: place else on the same line as the closing brace.

The conventional Swift style (per Swift API Design Guidelines and common linters) keeps } else together.

✏️ Style fix
         if logoPath.hasPrefix("file://") {
             let path = logoPath.replacingOccurrences(of: "file://", with: "")
             if let image = UIImage(contentsOfFile: path) { return image }
-        }
-        else if logoPath.hasPrefix("/") {
+        } else if logoPath.hasPrefix("/") {
             if let image = UIImage(contentsOfFile: logoPath) { return image }
-        }
-        else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
+        } else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift around lines 28 - 30, The
closing brace and the else are split across lines in the conditional that checks
logoPath.hasPrefix("/") and tries UIImage(contentsOfFile:), violating Swift
style; change the block so the else is on the same line as the preceding closing
brace (e.g., transform the pattern used around logoPath.hasPrefix("/") and the
UIImage(contentsOfFile:) return into a single `} else if` line) to conform to
the Swift style guide.

37-37: Clarify intent: logoPath falls back to asset catalog lookup.

Line 37 tries UIImage(named: logoPath) as a final fallback, meaning logoPath can also be a bundle asset name. This overlaps with the logoName fallback in the initializer (lines 15-17). If intentional, a brief comment would help future maintainers understand why both exist.

+        // Fallback: treat logoPath as an asset catalog name
         if let image = UIImage(named: logoPath) { return image }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift at line 37, The code
attempts UIImage(named: logoPath) as a final fallback even though logoName is
already used in the initializer; add a short inline comment next to the
UIImage(named: logoPath) call explaining that this is intentional because
logoPath may refer to an asset catalog name (not just a file path/URL) and
therefore overlaps with logoName fallback, so future maintainers understand the
redundancy is deliberate; reference the UIImage(named:), logoPath variable and
the initializer that sets logoName when adding the comment.

24-26: Consider using URL for cleaner file:// handling.

Manually stripping the file:// prefix works, but using URL(string:)?.path is more robust and handles edge cases (e.g., percent-encoded paths).

♻️ Suggested improvement
         if logoPath.hasPrefix("file://") {
-            let path = logoPath.replacingOccurrences(of: "file://", with: "")
-            if let image = UIImage(contentsOfFile: path) { return image }
+            if let fileURL = URL(string: logoPath), fileURL.isFileURL,
+               let image = UIImage(contentsOfFile: fileURL.path) {
+                return image
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift around lines 24 - 26,
Replace the manual "file://" prefix stripping with URL parsing: in the block
referencing logoPath.hasPrefix("file://") and UIImage(contentsOfFile:), create a
URL from logoPath (e.g., URL(string: logoPath)?.path) to obtain the filesystem
path (which handles percent-encoding and edge cases) and pass that path into
UIImage(contentsOfFile:); ensure you still fall back to the existing behavior if
URL creation fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift:
- Around line 31-36: The code currently blocks using Data(contentsOf: url) when
logoPath is an http(s) URL; replace this synchronous network call in the
UIImage+UsercentricsLogoDict extension: either (preferred) change the API to
load remote images asynchronously (add a helper like
loadRemoteImageAsync(url:completion:) that uses URLSession.shared.dataTask(with:
URLRequest(url: url, timeoutInterval: X)) and invokes the completion on the main
thread to set the image, or (minimal defensive) assert(!Thread.isMainThread) in
the http(s) branch and perform a synchronous fetch with URLSession and a
semaphore/timeout to avoid indefinite hangs; update the branch that checks
logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://") to use the
chosen approach and remove Data(contentsOf: url).

---

Nitpick comments:
In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift:
- Around line 28-30: The closing brace and the else are split across lines in
the conditional that checks logoPath.hasPrefix("/") and tries
UIImage(contentsOfFile:), violating Swift style; change the block so the else is
on the same line as the preceding closing brace (e.g., transform the pattern
used around logoPath.hasPrefix("/") and the UIImage(contentsOfFile:) return into
a single `} else if` line) to conform to the Swift style guide.
- Line 37: The code attempts UIImage(named: logoPath) as a final fallback even
though logoName is already used in the initializer; add a short inline comment
next to the UIImage(named: logoPath) call explaining that this is intentional
because logoPath may refer to an asset catalog name (not just a file path/URL)
and therefore overlaps with logoName fallback, so future maintainers understand
the redundancy is deliberate; reference the UIImage(named:), logoPath variable
and the initializer that sets logoName when adding the comment.
- Around line 24-26: Replace the manual "file://" prefix stripping with URL
parsing: in the block referencing logoPath.hasPrefix("file://") and
UIImage(contentsOfFile:), create a URL from logoPath (e.g., URL(string:
logoPath)?.path) to obtain the filesystem path (which handles percent-encoding
and edge cases) and pass that path into UIImage(contentsOfFile:); ensure you
still fall back to the existing behavior if URL creation fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8a2f62d4-a76d-42ff-8fd0-a4731d2af8a6

📥 Commits

Reviewing files that changed from the base of the PR and between a3f7a22 and c61f77d.

📒 Files selected for processing (1)
  • ios/Extensions/UIImage+UsercentricsLogoDict.swift

Comment on lines +31 to +36
else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
let url = URL(string: logoPath),
let data = try? Data(contentsOf: url),
let image = UIImage(data: data) {
return image
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Synchronous network request will block the calling thread.

Data(contentsOf: url) performs a blocking network call. If the initializer is invoked on the main thread (typical for UI setup code), this will freeze the UI and could trigger watchdog termination on slow or unreachable networks.

Consider one of the following approaches:

  1. Load remote images asynchronously and update the UI via a completion handler or reactive binding.
  2. If synchronous loading is required, document that this must not be called from the main thread and add an assertion during development.
  3. Add a timeout to prevent indefinite hangs.
🛡️ Minimal defensive fix: assert off main thread + timeout
         else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
-                let url = URL(string: logoPath),
-                let data = try? Data(contentsOf: url),
-                let image = UIImage(data: data) {
+                let url = URL(string: logoPath) {
+            `#if` DEBUG
+            assert(!Thread.isMainThread, "Loading remote image synchronously on main thread is not allowed")
+            `#endif`
+            var request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 10)
+            if let data = try? Data(contentsOf: url, options: .uncached) {
+                if let image = UIImage(data: data) { return image }
+            }
             return image
         }

Note: A fully async solution is preferred but may require API changes to the initializer.

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

In `@ios/Extensions/UIImage`+UsercentricsLogoDict.swift around lines 31 - 36, The
code currently blocks using Data(contentsOf: url) when logoPath is an http(s)
URL; replace this synchronous network call in the UIImage+UsercentricsLogoDict
extension: either (preferred) change the API to load remote images
asynchronously (add a helper like loadRemoteImageAsync(url:completion:) that
uses URLSession.shared.dataTask(with: URLRequest(url: url, timeoutInterval: X))
and invokes the completion on the main thread to set the image, or (minimal
defensive) assert(!Thread.isMainThread) in the http(s) branch and perform a
synchronous fetch with URLSession and a semaphore/timeout to avoid indefinite
hangs; update the branch that checks logoPath.hasPrefix("http://") ||
logoPath.hasPrefix("https://") to use the chosen approach and remove
Data(contentsOf: url).

Comment on lines +24 to +26
if logoPath.hasPrefix("file://") {
let path = logoPath.replacingOccurrences(of: "file://", with: "")
if let image = UIImage(contentsOfFile: path) { return image }
Copy link

Choose a reason for hiding this comment

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

Suggestion: Stripping file:// via string replacement can produce invalid filesystem paths for percent-encoded file URLs (for example spaces encoded as %20), causing local images to fail to load. Parse the value as a URL and use its .path to get a valid decoded file path. [logic error]

Severity Level: Major ⚠️
- ⚠️ Local `file://` logos may not render reliably.
- ⚠️ Banner branding can disappear for encoded file paths.
Suggested change
if logoPath.hasPrefix("file://") {
let path = logoPath.replacingOccurrences(of: "file://", with: "")
if let image = UIImage(contentsOfFile: path) { return image }
if logoPath.hasPrefix("file://"), let fileURL = URL(string: logoPath) {
if let image = UIImage(contentsOfFile: fileURL.path) { return image }
Steps of Reproduction ✅
1. Build banner settings with a logo dictionary path that starts with `file://` (logo
parsing entrypoint: `ios/Extensions/BannerSettings+Dict.swift:36`, `123-124`).

2. Pass settings through normal banner APIs (`src/Usercentrics.tsx:38-45` ->
`ios/RNUsercentricsModule.swift:82`/`97` -> `BannerSettings(from:)`).

3. When `logoPath` contains URL-escaped characters (e.g. `%20`), current code strips
prefix by string replacement at `ios/Extensions/UIImage+UsercentricsLogoDict.swift:24-26`
and feeds encoded path to `UIImage(contentsOfFile:)`.

4. Image load fails for that path format; using `URL(string:).path` decodes correctly and
restores local-file loading.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** ios/Extensions/UIImage+UsercentricsLogoDict.swift
**Line:** 24:26
**Comment:**
	*Logic Error: Stripping `file://` via string replacement can produce invalid filesystem paths for percent-encoded file URLs (for example spaces encoded as `%20`), causing local images to fail to load. Parse the value as a URL and use its `.path` to get a valid decoded file path.

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.
👍 | 👎

else if logoPath.hasPrefix("/") {
if let image = UIImage(contentsOfFile: logoPath) { return image }
}
else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
Copy link

Choose a reason for hiding this comment

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

Suggestion: The HTTP/HTTPS branch performs a synchronous network read with Data(contentsOf:), and this initializer is invoked from the main queue during banner setup. That can block the UI thread and freeze banner presentation. Avoid synchronous network loading in this path (or at least skip it on the main thread) and only use already-local image sources here. [possible bug]

Severity Level: Major ⚠️
- ❌ Banner presentation can freeze during remote logo fetch.
- ⚠️ `showFirstLayer`/`showSecondLayer` responsiveness degrades on slow networks.
Suggested change
else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
else if (logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://")),
!Thread.isMainThread,
Steps of Reproduction ✅
1. Trigger banner display via public API `Usercentrics.showFirstLayer(options)` in
`src/Usercentrics.tsx:38-40`.

2. Native bridge executes `RNUsercentricsModule.showFirstLayer` on `DispatchQueue.main`
(`ios/RNUsercentricsModule.swift:23`, `73-85`), then builds `BannerSettings(from:)`.

3. Settings parsing calls `UIImage(from:)` through `GeneralStyleSettings`
(`ios/Extensions/BannerSettings+Dict.swift:28-37`), then `image(fromLogoPath:)`
(`ios/Extensions/UIImage+UsercentricsLogoDict.swift:23-35`).

4. Provide `logo.logoPath` as `https://...` (same serialized dictionary flow used in tests
at `sample/ios/sampleTests/RNUsercentricsModuleTests.swift:485`); `Data(contentsOf:)` runs
synchronously on main thread and can stall banner rendering/UI.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** ios/Extensions/UIImage+UsercentricsLogoDict.swift
**Line:** 31:31
**Comment:**
	*Possible Bug: The HTTP/HTTPS branch performs a synchronous network read with `Data(contentsOf:)`, and this initializer is invoked from the main queue during banner setup. That can block the UI thread and freeze banner presentation. Avoid synchronous network loading in this path (or at least skip it on the main thread) and only use already-local image sources here.

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
Copy link

codeant-ai bot commented Mar 19, 2026

CodeAnt AI finished reviewing your PR.

Comment on lines +31 to +35
else if logoPath.hasPrefix("http://") || logoPath.hasPrefix("https://"),
let url = URL(string: logoPath),
let data = try? Data(contentsOf: url),
let image = UIImage(data: data) {
return image

Choose a reason for hiding this comment

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

Action required

1. Main-thread image download 🐞 Bug ➹ Performance

UIImage.image(fromLogoPath:) performs a synchronous Data(contentsOf:) fetch for http(s) paths,
and this logo parsing runs on DispatchQueue.main during showFirstLayer/showSecondLayer. A remote
logoPath will block the UI thread while downloading, potentially freezing the app and triggering
watchdog termination.
Agent Prompt
## Issue description
`UIImage.image(fromLogoPath:)` uses `Data(contentsOf:)` for `http(s)` logo paths. Because `BannerSettings(from:)` is built on `DispatchQueue.main` in `RNUsercentricsModule.showFirstLayer/showSecondLayer`, a remote `logoPath` will synchronously block the main thread.

## Issue Context
- `RNUsercentricsModule.queue` is set to `DispatchQueue.main`, and `BannerSettings(from: dict)` is created inside `queue.async`.
- `BannerSettings` parsing calls `UIImage(from:)` for the logo.
- `UIImage(from:)` calls `image(fromLogoPath:)`, which includes an `http(s)` branch using synchronous `Data(contentsOf:)`.

## Fix Focus Areas
- ios/Extensions/UIImage+UsercentricsLogoDict.swift[31-36]
- ios/RNUsercentricsModule.swift[22-85]
- ios/Extensions/BannerSettings+Dict.swift[27-48]

## Suggested fix approach
- Do not perform any network I/O inside `UIImage` initializers.
- Either:
  1) Remove the `http(s)` branch entirely (treat remote URLs as unsupported for `logoPath`), and rely on a separate async loader elsewhere, or
  2) Redesign the logo-loading flow to be asynchronous (e.g., pass `URL`/string through settings, fetch via `URLSession` off-main-thread, then update the banner UI when the image arrives).
- If you must keep remote support, ensure the fetch happens off the main thread and has timeouts/error handling, and avoid blocking the caller.

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

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 20, 2026

CI Feedback 🧐

(Feedback updated until commit c61f77d)

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-ios

Failed stage: Run tests [❌]

Failed test name: ""

Failure summary:

The GitHub Action failed during the iOS build step (Xcode exit code 65), so tests were cancelled
before they could run.
The build failed while compiling the CocoaPods target
react-native-usercentrics:
- Swift compilation failed with repeated errors Cannot find type
GppSectionChangePayload in scope.
- This caused EmitSwiftModule normal arm64 / SwiftEmitModule ...
react_native_usercentrics (target react-native-usercentrics from project Pods) to fail, which
aborted the build and led to Testing cancelled because the build failed and ** TEST FAILED **.

Warnings about the run script phase Create Symlinks to Header Folders running every build and
“Skipping duplicate build file” messages are present, but they are not the direct cause of the
failure.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

958:  Installing React-RCTText (0.81.4)
959:  Installing React-RCTVibration (0.81.4)
960:  Installing React-RuntimeApple (0.81.4)
961:  Installing React-RuntimeCore (0.81.4)
962:  Installing React-RuntimeHermes (0.81.4)
963:  Installing React-callinvoker (0.81.4)
964:  Installing React-cxxreact (0.81.4)
965:  Installing React-debug (0.81.4)
966:  Installing React-defaultsnativemodule (0.81.4)
967:  Installing React-domnativemodule (0.81.4)
968:  Installing React-featureflags (0.81.4)
969:  Installing React-featureflagsnativemodule (0.81.4)
970:  Installing React-graphics (0.81.4)
971:  Installing React-hermes (0.81.4)
972:  Installing React-idlecallbacksnativemodule (0.81.4)
973:  Installing React-jserrorhandler (0.81.4)
974:  Installing React-jsi (0.81.4)
...

1212:  ▸ Copying ExecutionContextManager.h
1213:  ▸ Copying ExecutionContext.h
1214:  ▸ Copying ConsoleMessage.h
1215:  ▸ Copying Base64.h
1216:  ▸ Copying React-jsiexecutor-umbrella.h
1217:  ▸ Copying JSINativeModules.h
1218:  ▸ Copying JSIExecutor.h
1219:  ▸ Copying threadsafe.h
1220:  ▸ Copying jsilib.h
1221:  ▸ Copying jsi.h
1222:  ▸ Copying jsi-inl.h
1223:  ▸ Copying instrumentation.h
1224:  ▸ Copying decorator.h
1225:  ▸ Copying React-jsi-umbrella.h
1226:  ▸ Copying JSIDynamic.h
1227:  ▸ Copying React-jserrorhandler-umbrella.h
1228:  ▸ Copying React-idlecallbacksnativemodule-umbrella.h
1229:  ▸ Copying HermesExecutorFactory.h
1230:  ▸ Copying React-hermes-umbrella.h
1231:  ▸ Copying React-graphics-umbrella.h
1232:  ▸ Copying React-featureflagsnativemodule-umbrella.h
1233:  ▸ Copying React-featureflags-umbrella.h
1234:  ▸ Copying React-domnativemodule-umbrella.h
1235:  ▸ Copying React-defaultsnativemodule-umbrella.h
1236:  ▸ Copying React-debug-umbrella.h
1237:  ▸ Copying TraceSection.h
1238:  ▸ Copying SystraceSection.h
1239:  ▸ Copying SharedProxyCxxModule.h
1240:  ▸ Copying RecoverableError.h
1241:  ▸ Copying ReactNativeVersion.h
...

1244:  ▸ Copying RAMBundleRegistry.h
1245:  ▸ Copying NativeToJsBridge.h
1246:  ▸ Copying NativeModule.h
1247:  ▸ Copying MoveWrapper.h
1248:  ▸ Copying ModuleRegistry.h
1249:  ▸ Copying MethodCall.h
1250:  ▸ Copying MessageQueueThread.h
1251:  ▸ Copying JsArgumentHelpers.h
1252:  ▸ Copying JsArgumentHelpers-inl.h
1253:  ▸ Copying JSModulesUnbundle.h
1254:  ▸ Copying JSIndexedRAMBundle.h
1255:  ▸ Copying JSExecutor.h
1256:  ▸ Copying JSBundleType.h
1257:  ▸ Copying JSBigString.h
1258:  ▸ Copying Instance.h
1259:  ▸ Copying ErrorUtils.h
1260:  ▸ Copying CxxNativeModule.h
...

1603:  ▸ Copying RCTI18nUtil.h
1604:  ▸ Copying RCTI18nManager.h
1605:  ▸ Copying RCTHTTPRequestHandler.h
1606:  ▸ Copying RCTGIFImageDecoder.h
1607:  ▸ Copying RCTFrameUpdate.h
1608:  ▸ Copying RCTFrameAnimation.h
1609:  ▸ Copying RCTFont.h
1610:  ▸ Copying RCTFileRequestHandler.h
1611:  ▸ Copying RCTFileReaderModule.h
1612:  ▸ Copying RCTFPSGraph.h
1613:  ▸ Copying RCTExceptionsManager.h
1614:  ▸ Copying RCTEventEmitter.h
1615:  ▸ Copying RCTEventDispatcherProtocol.h
1616:  ▸ Copying RCTEventDispatcher.h
1617:  ▸ Copying RCTEventAnimation.h
1618:  ▸ Copying RCTErrorInfo.h
1619:  ▸ Copying RCTErrorCustomizer.h
1620:  ▸ Copying RCTDynamicTypeRamp.h
...

1832:  ▸ Compiling SocketRocket-dummy.m
1833:  ▸ Compiling SRWebSocket.m
1834:  ▸ Compiling SRURLUtilities.m
1835:  ▸ Compiling SRSecurityPolicy.m
1836:  ▸ Compiling SRSIMDHelpers.m
1837:  ▸ Compiling SRRunLoopThread.m
1838:  ▸ Compiling SRRandom.m
1839:  ▸ Compiling SRProxyConnect.m
1840:  ▸ Compiling SRPinningSecurityPolicy.m
1841:  ▸ Compiling SRMutex.m
1842:  ▸ Compiling SRLog.m
1843:  ▸ Compiling SRIOConsumerPool.m
1844:  ▸ Compiling SRIOConsumer.m
1845:  ▸ Compiling SRHash.m
1846:  ▸ Compiling SRHTTPConnectMessage.m
1847:  ▸ Compiling SRError.m
1848:  ▸ Compiling SRDelegateController.m
...

2227:  ▸ Compiling RCTModalHostViewManager.m
2228:  ▸ Compiling RCTModalHostViewController.m
2229:  ▸ Compiling RCTModalHostView.m
2230:  ▸ Compiling RCTLayoutAnimationGroup.m
2231:  ▸ Compiling RCTLayoutAnimation.m
2232:  ▸ Compiling React-Core-dummy.m
2233:  ▸ Compiling RCTLayout.m
2234:  ▸ Compiling RCTKeyCommands.m
2235:  ▸ Compiling RCTJSThread.m
2236:  ▸ Compiling RCTJSStackFrame.m
2237:  ▸ Compiling RCTImageSource.m
2238:  ▸ Compiling RCTI18nUtil.m
2239:  ▸ Compiling RCTFrameUpdate.m
2240:  ▸ Compiling RCTEventEmitter.m
2241:  ▸ Compiling RCTEventDispatcher.m
2242:  ▸ Compiling RCTErrorInfo.m
2243:  ▸ Compiling RCTDisplayLink.m
...

2279:  ▸ Compiling RCTInputAccessoryViewContent.mm
2280:  ▸ Compiling RCTInputAccessoryView.mm
2281:  ▸ Compiling RCTInputAccessoryShadowView.mm
2282:  ▸ Compiling RCTDynamicTypeRamp.mm
2283:  ▸ Compiling RCTConvert+Text.mm
2284:  ▸ Compiling RCTBaseTextViewManager.mm
2285:  ▸ Compiling RCTBaseTextShadowView.mm
2286:  ▸ Compiling RCTBaseTextInputViewManager.mm
2287:  ▸ Compiling RCTBaseTextInputView.mm
2288:  ▸ Compiling RCTBaseTextInputShadowView.mm
2289:  ▸ Compiling RCTBackedTextInputDelegateAdapter.mm
2290:  ▸ Compiling RCTText_vers.c
2291:  ▸ Compiling React-RCTText-dummy.m
2292:  ▸ Touching ReactCommon.framework (in target 'ReactCommon' from project 'Pods')
2293:  ▸ Touching reacthermes.framework (in target 'React-hermes' from project 'Pods')
2294:  ▸ Processing React-jserrorhandler-Info.plist
2295:  ▸ Processing React-Core-Info.plist
2296:  ▸ Compiling StackTraceParser.cpp
2297:  ▸ Compiling JsErrorHandler.cpp
2298:  ▸ Compiling NSTextStorage+FontScaling.m
2299:  ▸ Compiling React_jserrorhandler_vers.c
2300:  ▸ Compiling React-jserrorhandler-dummy.m
2301:  ▸ Touching React_graphics.framework (in target 'React-graphics' from project 'Pods')
2302:  ▸ Compiling RCTTypedModuleConstants.mm
2303:  ▸ Compiling RCTConvertHelpers.mm
2304:  ▸ Compiling RCTTypeSafety_vers.c
2305:  ▸ Running script 'Create Symlinks to Header Folders'
2306:  ▸ Touching React_jserrorhandler.framework (in target 'React-jserrorhandler' from project 'Pods')
2307:  ▸ Touching React.framework (in target 'React-Core' from project 'Pods')
...

2825:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ComponentDescriptors.cpp (in target 'ReactCodegen' from project 'Pods')
2826:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2827:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2828:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2829:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2830:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2831:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2832:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2833:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2834:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2835:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2836:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2837:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2838:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'ReactCodegen' from project 'Pods')
2839:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-utils' from project 'Pods')
2840:  Testing failed:
2841:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-runtimescheduler' from project 'Pods')
2842:  Cannot find type 'GppSectionChangePayload' in scope
2843:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-runtimeexecutor' from project 'Pods')
2844:  Cannot find type 'GppSectionChangePayload' in scope
2845:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-rendererconsistency' from project 'Pods')
2846:  Cannot find type 'GppSectionChangePayload' in scope
2847:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-microtasksnativemodule' from project 'Pods')
2848:  Cannot find type 'GppSectionChangePayload' in scope
2849:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsitooling' from project 'Pods')
2850:  Cannot find type 'GppSectionChangePayload' in scope
2851:  Cannot find type 'GppSectionChangePayload' in scope
2852:  Testing cancelled because the build failed.
2853:  ** TEST FAILED **
2854:  The following build commands failed:
2855:  EmitSwiftModule normal arm64 (in target 'react-native-usercentrics' from project 'Pods')
2856:  SwiftEmitModule normal arm64 Emitting\ module\ for\ react_native_usercentrics (in target 'react-native-usercentrics' from project 'Pods')
2857:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectortracing' from project 'Pods')
2858:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectornetwork' from project 'Pods')
2859:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectorcdp' from project 'Pods')
2860:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jserrorhandler' from project 'Pods')
2861:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-idlecallbacksnativemodule' from project 'Pods')
...

2866:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-defaultsnativemodule' from project 'Pods')
2867:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-debug' from project 'Pods')
2868:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeHermes' from project 'Pods')
2869:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeCore' from project 'Pods')
2870:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeApple' from project 'Pods')
2871:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RCTRuntime' from project 'Pods')
2872:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RCTFBReactNativeSpec' from project 'Pods')
2873:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-NativeModulesApple' from project 'Pods')
2874:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-Mapbuffer' from project 'Pods')
2875:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-ImageManager' from project 'Pods')
2876:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-FabricImage' from project 'Pods')
2877:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-FabricComponents' from project 'Pods')
2878:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-Fabric' from project 'Pods')
2879:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'RCT-Folly' from project 'Pods')
2880:  Testing workspace sample with scheme sample
2881:  (3 failures)
2882:  ##[error]Process completed with exit code 65.
2883:  ##[group]Run actions/upload-artifact@v4

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants