Skip to content

fix(harmony): prepend file:// scheme to getURL() to enable local image loading from hot update bundle#597

Merged
sunnylqm merged 1 commit into
masterfrom
fix/harmony-image-hot-update
Jul 1, 2026
Merged

fix(harmony): prepend file:// scheme to getURL() to enable local image loading from hot update bundle#597
sunnylqm merged 1 commit into
masterfrom
fix/harmony-image-hot-update

Conversation

@sunnylqm

@sunnylqm sunnylqm commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This PR fixes local image assets (imported via require('./image.png')) not displaying when loaded from a hot-updated bundle on React Native OpenHarmony.

Root Cause

  1. In React Native's AssetSourceResolver.harmony.ts, local assets resolve relative to the bundle URL if and only if the bundle URL starts with the file:// scheme.
  2. Previously, PushyFileJSBundleProvider.ets's getURL() returned the raw absolute path (/data/storage/.../bundle.harmony.js) without the file:// prefix.
  3. This caused AssetSourceResolver to resolve the asset's URI as asset://assets/.../image.png, which ArkUI's RNImage.ets compiles into a compile-time $rawfile(...) macro. Since hot-updated assets reside in the sandbox at runtime, this lookup failed, resulting in blank/invisible images.
  4. Prepending file:// to getURL() causes AssetSourceResolver to resolve local assets as file:///data/storage/.../assets/image.png, which ArkUI's Image() component can load directly from the device's sandbox.

Summary by CodeRabbit

  • Bug Fixes
    • Improved bundle URL handling so file paths are consistently returned with the correct file:// format.
    • Fixed cases where non-file:// paths could be returned without normalization, helping ensure more reliable app loading behavior.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The getURL() method in PushyFileJSBundleProvider.ets was modified to normalize the bundle URL path by prefixing it with "file://" when the resolved path does not already have that prefix, rather than returning the raw path directly.

Changes

URL Normalization

Layer / File(s) Summary
getURL path normalization
harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets
getURL() stores updateContext.getBundleUrl() in a local path variable and conditionally prefixes it with file:// if not already present.

Estimated code review effort: 1 (Trivial) | ~2 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main fix: adding file:// to getURL() for hot-update bundle image loading.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/harmony-image-hot-update

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.

@sunnylqm sunnylqm merged commit a1db307 into master Jul 1, 2026
3 of 4 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets (1)

19-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent path normalization between getURL() and getBundle().

getURL() now returns a file://-prefixed path, but getBundle() (lines 27-37) continues to use the raw path from updateContext.getBundleUrl() for filesystem operations (fs.access) and the returned filePath. This is likely intentional since @ohos.file.fs APIs expect raw sandbox paths, not URI schemes. However, this creates a subtle contract where two methods on the same provider return different path formats for the same logical resource.

Consider adding a clarifying code comment in getURL() explaining why getBundle() deliberately does not prefix, to prevent future maintainers from "fixing" the inconsistency and breaking filesystem access.

  getURL(): string {
    // AssetSourceResolver expects file:// URIs for local asset resolution,
    // while fs.access in getBundle() requires raw sandbox paths.
    const path = this.updateContext.getBundleUrl();
    ...
  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets` around lines 19 -
23, The path format is intentionally different between getURL() and getBundle(),
so add a clarifying comment in PushyFileJSBundleProvider.ets around getURL()
explaining that it returns a file:// URI for asset resolution while getBundle()
must keep using the raw updateContext.getBundleUrl() value for fs.access and
filePath handling. Use the getURL() and getBundle() methods as the anchor points
so future maintainers do not “normalize” both paths and break filesystem access.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets`:
- Around line 18-24: getURL() may return undefined despite being declared as
returning string, because PushyFileJSBundleProvider.getURL falls through to
return path when updateContext.getBundleUrl() is empty or undefined. Update
getURL() to explicitly handle the falsy path case by returning a valid string,
or change the method signature to string | undefined if that is the intended
contract, while keeping the existing file:// prefix logic intact.

---

Nitpick comments:
In `@harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets`:
- Around line 19-23: The path format is intentionally different between getURL()
and getBundle(), so add a clarifying comment in PushyFileJSBundleProvider.ets
around getURL() explaining that it returns a file:// URI for asset resolution
while getBundle() must keep using the raw updateContext.getBundleUrl() value for
fs.access and filePath handling. Use the getURL() and getBundle() methods as the
anchor points so future maintainers do not “normalize” both paths and break
filesystem access.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acf21678-1939-4bec-be2f-8ec346c6b789

📥 Commits

Reviewing files that changed from the base of the PR and between cfce979 and d564496.

📒 Files selected for processing (1)
  • harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets

Comment on lines 18 to 24
getURL(): string {
return this.updateContext.getBundleUrl();
const path = this.updateContext.getBundleUrl();
if (path && !path.startsWith('file://')) {
return 'file://' + path;
}
return path;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

getURL() can return undefined violating its string return type.

this.updateContext.getBundleUrl() may return undefined (or empty string), and when path is falsy, the method falls through to return path (line 23), returning undefined despite the string type annotation. This could cause runtime issues for consumers expecting a valid URL string.

Add explicit handling for the undefined/empty case, or adjust the return type to string | undefined if that's the intended contract.

getURL(): string | undefined {
    const path = this.updateContext.getBundleUrl();
    if (!path) {
      return undefined;
    }
    if (!path.startsWith('file://')) {
      return 'file://' + path;
    }
    return path;
}

Or if empty path should never happen, throw or return empty string with a warning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets` around lines 18 -
24, getURL() may return undefined despite being declared as returning string,
because PushyFileJSBundleProvider.getURL falls through to return path when
updateContext.getBundleUrl() is empty or undefined. Update getURL() to
explicitly handle the falsy path case by returning a valid string, or change the
method signature to string | undefined if that is the intended contract, while
keeping the existing file:// prefix logic intact.

sunnylqm added a commit that referenced this pull request Jul 1, 2026
…cal image loading from hot update bundle (#597)"

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant