Skip to content

Fix asset color resolution for Xcode-built preview targets (#151)#152

Merged
obj-p merged 3 commits intomainfrom
fix/151-tabview-xcode-blank
Apr 30, 2026
Merged

Fix asset color resolution for Xcode-built preview targets (#151)#152
obj-p merged 3 commits intomainfrom
fix/151-tabview-xcode-blank

Conversation

@obj-p
Copy link
Copy Markdown
Owner

@obj-p obj-p commented Apr 30, 2026

Summary

  • Closes TabView page contents render blank/dimmed when previewing Xcode-built targets (.xcodeproj / .xcworkspace) #151. Bug was misnamed in the issue title — diagnosis showed the failure isn't about TabView but about Color(.brandPrimary) (and any ColorResource/ImageResource) silently resolving to no color when the bridge dylib is built against an Xcode framework target. ToDoView's TabView page bodies appeared blank because SummaryCard.background(color.gradient) painted nothing.
  • Root cause: Xcode-emitted Generated*Symbols.swift files use Bundle(for: ResourceBundleClass.self) to find the resource bundle. When recompiled into the bridge dylib, ResourceBundleClass lives in the dylib (no Assets.car), so asset lookups silently return nothing. SPM and Bazel weren't affected because their examples used system colors only — not because their build paths are immune.
  • Fix: XcodeBuildSystem now rewrites any Generated*Symbols.swift source on the way into Tier 2, replacing the broken preamble with Bundle(path: "<CODESIGNING_FOLDER_PATH>") ?? Bundle.main and writing the transformed copy to <DERIVED_FILE_DIR>/PreviewsMCPRewrites/.
  • Also adds Log.info in Compiler.compileCombined (extraFlags) and BuildHelpers.detectAndBuild (selected build system) — both were silent in serve.log and made the diagnosis painful.
  • Documents Xcode and Bazel artifact layouts uniformly with the existing SPM section in docs/build-system-integration.md.

Test plan

  • swift test --filter BuildSystem — 68/68 passing, including 4 new rewriteResourceBundle tests covering the happy path, two negative cases, and path-escape edge cases.
  • iOS snapshot of examples/xcodeproj/Sources/ToDo/ToDoView.swift renders the Progress card (blue gradient + "1/8" + "7 remaining" + page dots) correctly.
  • iOS snapshot of examples/xcworkspace/Sources/ToDo/ToDoView.swift renders correctly.
  • macOS snapshot of examples/xcodeproj/Sources/ToDo/ToDoView.swift renders correctly (no longer dim/translucent).
  • Targeted asset-color probe (system .blue control vs. Color.brandPrimary): brandPrimary now paints; before the fix it rendered as no-color.
  • Symbol audit: nm confirmed ResourceBundleClass lives in the Xcode bridge dylib but not in SPM's, matching the proposed mechanism.
  • SPM example still renders (no behavior change on that path).

🤖 Generated with Claude Code

obj-p and others added 3 commits April 30, 2026 09:56
`Generated*Symbols.swift` (asset/string/plist symbols emitted by Xcode)
contain a `Bundle(for: ResourceBundleClass.self)` lookup that resolves
to whichever binary defines `ResourceBundleClass`. When PreviewsMCP
recompiled these files into the Tier 2 bridge dylib, that binary became
the bridge dylib itself — which has no `Assets.car` — so `Color(.brandPrimary)`
and similar lookups silently returned nothing, leaving views (e.g.
ToDoView's TabView page bodies) blank under .xcodeproj/.xcworkspace.

XcodeBuildSystem now writes a transformed copy of each `Generated*Symbols.swift`
to `<DERIVED_FILE_DIR>/PreviewsMCPRewrites/`, replacing the resource-bundle
preamble with `Bundle(path: "<CODESIGNING_FOLDER_PATH>") ?? Bundle.main`.
SPM and Bazel paths are untouched.

Also adds `Log.info` lines in `Compiler.compileCombined` and
`BuildHelpers.detectAndBuild` (the build-system / extraFlags surface was
silent in serve.log, which made the original diagnosis painful), and
documents Xcode and Bazel artifact layouts uniformly with the existing
SPM section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the BUILT_PRODUCTS_DIR/WRAPPER_NAME fallback; CODESIGNING_FOLDER_PATH
  is the load-bearing input and the fallback could resolve to a non-existent
  path, silently re-introducing the bug it was meant to prevent.
- Add fileExists guard with a warning log when CODESIGNING_FOLDER_PATH
  doesn't point at a real wrapper on disk; fall back to the original
  sources rather than producing a Bundle(path:) that returns nil.
- Extract the rewrite loop into `applyResourceBundleRewrites(sources:settings:)`
  so it's directly testable without spinning up xcodebuild.
- Add three integration tests covering: happy-path fan-out across multiple
  Generated*Symbols.swift files, missing CODESIGNING_FOLDER_PATH, and
  CODESIGNING_FOLDER_PATH pointing at a non-existent path.
- Fixes the swift-format strict lint error at line 140.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 7 new tests in 1d4f43a pushed BuildSystemTests' struct body to
1025 lines, just past SwiftLint's 1000-line type_body_length cap.
Move them verbatim into ResourceBundleRewriteTests to keep both
suites under the cap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@obj-p obj-p merged commit bfe91c1 into main Apr 30, 2026
4 checks passed
@obj-p obj-p deleted the fix/151-tabview-xcode-blank branch April 30, 2026 19:44
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.

TabView page contents render blank/dimmed when previewing Xcode-built targets (.xcodeproj / .xcworkspace)

1 participant