Skip to content

chore: reproducible iOS builds + native artifact caching & verification#11301

Merged
NathanWalker merged 4 commits into
mainfrom
chore/stable-native-builds
Jul 2, 2026
Merged

chore: reproducible iOS builds + native artifact caching & verification#11301
NathanWalker merged 4 commits into
mainfrom
chore/stable-native-builds

Conversation

@edusperoni

Copy link
Copy Markdown
Contributor

PR Checklist

What is the current behavior?

Two problems with the native artifacts shipped in packages/core/platforms:

  1. iOS builds are non-deterministic. Rebuilding TNSWidgets.xcframework produces a different result depending on who/where it was built:

    • archive timestamps are not zeroed;
    • the dSYM Relocations/*.yml files embed the absolute, machine-specific build path;
    • the generated xcframework Info.plist reorders its AvailableLibraries between builds.
  2. No reliable link between the committed artifacts and their sources. The expensive native builds (Xcode xcframework, Gradle aar) aren't rebuilt in CI, and Nx's cache is environment-sensitive, so native source can be changed and committed without rebuilding the artifacts — and nothing catches the drift.

What is the new behavior?

Reproducible iOS build (packages/ui-mobile-base/ios/build.sh):

  • sets ZERO_AR_DATE=1 and -ffile-prefix-map=$(PWD)=. so archive timestamps and the absolute build path are stripped from the binaries/DWARF;
  • rewrites the machine-specific path prefix out of the dSYM Relocations/*.yml files;
  • normalizes the xcframework Info.plist by sorting AvailableLibraries by LibraryIdentifier, via a small normalize-xcframework-plist.mjs script (uses the plist package plus a whitespace-only postprocess to reproduce Apple's exact formatting byte-for-byte).

Native artifact caching & verification:

  • adds a content-addressed native-build-state.json that records, per platform, a hash of the native source inputs plus a hash of the produced artifact — an environment-independent link between sources and committed artifacts;
  • tools/native-state.mjs provides write / check / is-current;
  • the build target (and the build scripts) always build; a new opt-in ensure-native target (SKIP_NATIVE_IF_UNCHANGED=1) reuses committed artifacts only when the sources are unchanged;
  • a new native_artifacts_check CI workflow verifies on PRs that the committed artifacts are still in sync with their sources — pure content hashing, no Xcode/Android toolchain required.

Also adds plist ^5.0.0 as a root devDependency (used by the Info.plist normalizer) and refreshes the committed native artifacts via a full rebuild off main.

@nx-cloud

nx-cloud Bot commented Jul 2, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 2a0bcaa

Command Status Duration Result
nx test apps-automated -c=android ✅ Succeeded 3s View ↗
nx run-many --target=test --configuration=ci --... ✅ Succeeded <1s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-07-02 20:14:55 UTC

@edusperoni edusperoni requested a review from NathanWalker July 2, 2026 20:03
@NathanWalker NathanWalker merged commit 228b7f3 into main Jul 2, 2026
8 of 9 checks passed
@NathanWalker NathanWalker deleted the chore/stable-native-builds branch July 2, 2026 20:25
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.

2 participants