Skip to content

[SDK-476] Update RN to 0.81#862

Merged
lposen merged 4 commits into
feature/SDK-475-update-rn-version-to-0-80from
update/SDK-476-0-81
May 15, 2026
Merged

[SDK-476] Update RN to 0.81#862
lposen merged 4 commits into
feature/SDK-475-update-rn-version-to-0-80from
update/SDK-476-0-81

Conversation

@lposen
Copy link
Copy Markdown
Contributor

@lposen lposen commented May 6, 2026

🔹 JIRA Ticket(s) if any

✏️ Description

Please provide a brief description of what this pull request does.

@qltysh
Copy link
Copy Markdown

qltysh Bot commented May 6, 2026

Qlty


Coverage Impact

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Lines Statements Branches Functions
Coverage: 63%
63.07% (398/631) 40.07% (103/257) 61.5% (139/226)

android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="${usesCleartextTraffic}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The debug AndroidManifest.xml was removed and android:usesCleartextTraffic="${usesCleartextTraffic}" now lives in the main manifest, but example/android/app/build.gradle doesn't define a manifestPlaceholders value for usesCleartextTraffic in defaultConfig or per build type. Manifest merger will fail at assembleDebug/assembleRelease. This isn't caught by CI because the Unit Tests workflow only runs Jest — should we add the placeholders per the RN 0.81 template?

buildTypes {
    debug { manifestPlaceholders = [usesCleartextTraffic: "true"]; ... }
    release { manifestPlaceholders = [usesCleartextTraffic: "false"]; ... }
}

Also worth adding an ./gradlew assembleDebug step (and xcodebuild for iOS) to CI so future RN bumps don't ship broken example builds.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These changes come from React Natives Upgrade Helper, which outlines the tasks for updating between RN versions. I also checked in the scaffolding app suggested by react native, and it doesn't have the changes you suggest either. Perhaps the varible comes from RN?

I agree with adding the assembleDebug step to the CI, but it's out of scope for this upgrade.

Comment thread example/package.json
},
"engines": {
"node": ">=18"
"node": ">=20"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The root package.json has no engines field at all. If 20 is now the floor, should we set it on the published package too, to prevent consumers using Node 18 and install this fine only to break at build time on tooling internals.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's done via .nvmrc in the root package.

Copy link
Copy Markdown

@sumeruchat sumeruchat left a comment

Choose a reason for hiding this comment

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

Thanks Loren — the package alignment for 0.81.6 itself looks right (React 19.1.4, react-test-renderer 19.1.4, @react-native/* 0.81.6, CLI 20.0.0, TS ^5.8.3), and the Android template-shape changes (SDK 36, Gradle wrapper 8.14.3, deleted debug manifest, usesCleartextTraffic placeholder) are expected for 0.81.

Requesting changes on a few items before merge though — one is a hard blocker, the others matter given the team's stated plan that 0.81 is the last Legacy-Arch-capable release.

1. 🚨 Clean iOS example build is broken (blocker)
After wiping example/ios/Pods and Podfile.lock, pod install succeeds, but yarn example build:ios / direct xcodebuild fails in the ReactCodegen [CP-User] Generate Specs phase. The generated example/ios/build/generated/ios/ReactCodegen.podspec resolves the RN scripts dir to a non-existent absolute path:

RCT_SCRIPT_RN_DIR=\"$RCT_SCRIPT_POD_INSTALLATION_ROOT/../../../../../../../../../../../../../../../MyProjects/react-native-sdk/example/node_modules/react-native\"

which fails with:

/bin/sh: .../MyProjects/react-native-sdk/example/node_modules/react-native/scripts/xcode/with-environment.sh: No such file or directory

RN 0.81 codegen seems to be mis-resolving the workspace RN path from this example setup. Suggested fix: force a stable RN path in the Podfile (e.g. the repo-root ../../node_modules/react-native), then regenerate Pods from clean and re-verify. This needs to pass from a clean state before merge.

2. .nvmrc is below RN 0.81's Node minimum
react-native@0.81.6 declares engines.node >= 20.19.4 (called out as a breaking requirement in the 0.81 release notes), but .nvmrc is v20.19.0 and example/package.json engines only says >=20. Please bump both to >=20.19.4 (or a newer stable Node) — otherwise CI silently runs on an unsupported Node.

3. We can't actually prove Legacy Arch still works in this PR
Per the team plan, 0.81 is the last RN that supports Legacy Arch (0.82+ ignores the toggle). But the example here hard-forces New Arch on iOS via example/ios/Podfile:1 (ENV['RCT_NEW_ARCH_ENABLED'] = '1') and Info.plist:40-41, so RCT_NEW_ARCH_ENABLED=0 pod install/build is ignored unless the file is edited. Android defaults to newArchEnabled=true in example/android/gradle.properties:35. Net effect: we'd be shipping the supposed "last Legacy-supporting release" without ever verifying Legacy builds.

Recommendation: at minimum make the Podfile respect ENV.fetch('RCT_NEW_ARCH_ENABLED', '1'), and add a Legacy iOS/Android build path — either a CI matrix entry or a documented command — so we have an actual smoke test for the Legacy story we're telling consumers.

4. Android AGP pin (worth verifying or aligning)
android/build.gradle:12 and example/android/build.gradle:15 still pin AGP 8.7.2, while RN 0.81.6's Gradle plugin declares AGP 8.11.0 and the RN 0.81 template leaves the classpath unversioned. Paired with compileSdk/targetSdk = 36, this is worth aligning with RN 0.81/template or confirming Android CI passes cleanly under SDK 36. (I couldn't run Android locally — no Java on this box — so deferring final judgment to CI here.)

Non-blocking release-note items for consumers of the SDK on 0.81:

  • Node ≥ 20.19.4
  • Xcode ≥ 16.1
  • Android 16 / API 36 edge-to-edge + predictive-back behavior changes
  • Built-in JSC removal for apps not using Hermes

Other verification that did pass locally: yarn install --immutable, typecheck, lint, test (376), build, and git diff --check.

@lposen
Copy link
Copy Markdown
Contributor Author

lposen commented May 13, 2026

Thanks Loren — the package alignment for 0.81.6 itself looks right (React 19.1.4, react-test-renderer 19.1.4, @react-native/* 0.81.6, CLI 20.0.0, TS ^5.8.3), and the Android template-shape changes (SDK 36, Gradle wrapper 8.14.3, deleted debug manifest, usesCleartextTraffic placeholder) are expected for 0.81.

Requesting changes on a few items before merge though — one is a hard blocker, the others matter given the team's stated plan that 0.81 is the last Legacy-Arch-capable release.

1. 🚨 Clean iOS example build is broken (blocker) After wiping example/ios/Pods and Podfile.lock, pod install succeeds, but yarn example build:ios / direct xcodebuild fails in the ReactCodegen [CP-User] Generate Specs phase. The generated example/ios/build/generated/ios/ReactCodegen.podspec resolves the RN scripts dir to a non-existent absolute path:

RCT_SCRIPT_RN_DIR=\"$RCT_SCRIPT_POD_INSTALLATION_ROOT/../../../../../../../../../../../../../../../MyProjects/react-native-sdk/example/node_modules/react-native\"

which fails with:

/bin/sh: .../MyProjects/react-native-sdk/example/node_modules/react-native/scripts/xcode/with-environment.sh: No such file or directory

RN 0.81 codegen seems to be mis-resolving the workspace RN path from this example setup. Suggested fix: force a stable RN path in the Podfile (e.g. the repo-root ../../node_modules/react-native), then regenerate Pods from clean and re-verify. This needs to pass from a clean state before merge.

2. .nvmrc is below RN 0.81's Node minimum react-native@0.81.6 declares engines.node >= 20.19.4 (called out as a breaking requirement in the 0.81 release notes), but .nvmrc is v20.19.0 and example/package.json engines only says >=20. Please bump both to >=20.19.4 (or a newer stable Node) — otherwise CI silently runs on an unsupported Node.

3. We can't actually prove Legacy Arch still works in this PR Per the team plan, 0.81 is the last RN that supports Legacy Arch (0.82+ ignores the toggle). But the example here hard-forces New Arch on iOS via example/ios/Podfile:1 (ENV['RCT_NEW_ARCH_ENABLED'] = '1') and Info.plist:40-41, so RCT_NEW_ARCH_ENABLED=0 pod install/build is ignored unless the file is edited. Android defaults to newArchEnabled=true in example/android/gradle.properties:35. Net effect: we'd be shipping the supposed "last Legacy-supporting release" without ever verifying Legacy builds.

Recommendation: at minimum make the Podfile respect ENV.fetch('RCT_NEW_ARCH_ENABLED', '1'), and add a Legacy iOS/Android build path — either a CI matrix entry or a documented command — so we have an actual smoke test for the Legacy story we're telling consumers.

4. Android AGP pin (worth verifying or aligning) android/build.gradle:12 and example/android/build.gradle:15 still pin AGP 8.7.2, while RN 0.81.6's Gradle plugin declares AGP 8.11.0 and the RN 0.81 template leaves the classpath unversioned. Paired with compileSdk/targetSdk = 36, this is worth aligning with RN 0.81/template or confirming Android CI passes cleanly under SDK 36. (I couldn't run Android locally — no Java on this box — so deferring final judgment to CI here.)

Non-blocking release-note items for consumers of the SDK on 0.81:

  • Node ≥ 20.19.4
  • Xcode ≥ 16.1
  • Android 16 / API 36 edge-to-edge + predictive-back behavior changes
  • Built-in JSC removal for apps not using Hermes

Other verification that did pass locally: yarn install --immutable, typecheck, lint, test (376), build, and git diff --check.

Thank you for this really detailed response! I'll go through them one by one.

  1. I pushed a change. Please make sure to do yarn install in both the root and the example folder, then ios instructions in the README (below), then run again.
    Screenshot 2026-05-13 at 4 32 12 PM

  2. Good call regarding the .nvmrc. Updated. Regarding the node version in the package.json, this is taken directly from the React Native Upgrade Helper, which specifies how to update RN files.

  3. This was the same as before. We would test it by temporarily altering these values and building. No changes here.

  4. Where did you find this? The React Native Upgrade Helper doesn't mention changes to those files. The scaffolding library that RN suggests to use also points to 8.7.2.

@lposen lposen closed this May 13, 2026
@lposen lposen reopened this May 14, 2026
Copy link
Copy Markdown

@sumeruchat sumeruchat left a comment

Choose a reason for hiding this comment

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

Thanks Loren — re-tested the latest (4c3fb4c) end-to-end this time, including a full Android build now that I've got Java 17 wired up locally. Almost everything from my previous review either landed correctly or was a fair pushback. Approving with details below, plus one new finding worth addressing in this PR.

Resolutions / retractions from my prior review

1. iOS clean build is now ✅
Followed the exact flow from example/README.md — wiped example/ios/Pods, Podfile.lock, build/, then root yarn install, example yarn install, cd example/ios && bundle install && bundle exec pod install, then a Debug-simulator xcodebuild. bundle exec pod install used the Gemfile-pinned CocoaPods 1.15.2, and the generated ReactCodegen script now has a sane:

RCT_SCRIPT_RN_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT/../node_modules/react-native"

Build ended with ** BUILD SUCCEEDED **. The earlier codegen-path issue was caused by a CocoaPods version mismatch on my end (raw pod install instead of bundle exec). My bad on that — 4c3fb4c9 looks correct.

2. example/package.json engines (retracted)
Confirmed: the official RN 0.81.6 community template package.json sets "engines": { "node": ">=20" }, and the Upgrade Helper diff matches that. The important fix was .nvmrc, which you've done (20.19.4). Keeping example/package.json at >=20 is the right call.

3. Legacy Architecture testing (retracted as blocker)
Fair — manual flip-the-flag-and-build is the team's accepted process. Still think an env-toggleable Podfile (ENV.fetch('RCT_NEW_ARCH_ENABLED', '1')) plus a CI matrix entry would be useful given 0.81 is the last RN that supports Legacy Arch, but happy to treat that as a separate hardening ticket if you'd rather not pile it onto this PR.

4. AGP pin (downgraded to cleanup nit)
You're right that the Upgrade Helper diff doesn't change AGP and the official RN 0.81 template leaves classpath("com.android.tools.build:gradle") unversioned. That said, the RN 0.81.6 Gradle plugin source itself does define agp = "8.11.0" in node_modules/@react-native/gradle-plugin/gradle/libs.versions.toml, so 8.11.0 is the RN-sourced AGP. I verified locally that 8.7.2 builds just fine here under SDK 36 + RN 0.81.6 (clean ./gradlew :app:assembleDebug succeeded, 189 tasks, ~8.5 min). So this is cleanup, not a blocker — feel free to leave it.

🚨 New finding: Android clean build is broken by an rnc-cli permission bit (worth fixing in this PR)

Hit this on a fresh yarn install: cd example/android && ./gradlew :app:assembleDebug fails at example/android/settings.gradle:3 with exit code 126.

Root cause:

  • @react-native-community/cli@20.0.0 publishes build/bin.js as 0644 (not executable).
  • Yarn 3's node-modules linker creates .bin/rnc-cli as a plain symlink to that non-executable file.
  • RN 0.81's ReactSettingsExtension defaults to npx @react-native-community/cli config for Gradle autolinking → sh: .../example/node_modules/.bin/rnc-cli: Permission denied.

Direct repro:

cd example && npx @react-native-community/cli config
# → sh: .../example/node_modules/.bin/rnc-cli: Permission denied

And the workaround that proves the cause:

node ../node_modules/@react-native-community/cli/build/bin.js config --platform android
# → works

This was actually exposed by the upgrade chain (CLI 20.0.0 came in with #861, but RN 0.81's ReactSettingsExtension is what now invokes it via npx). Two suggested fixes — happy with either:

Option A — override autolink command in example/android/settings.gradle (cleanest, doesn't depend on chmod surviving installs):

plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
  ex.autolinkLibrariesFromCommand(
    ["node", file("../node_modules/@react-native-community/cli/build/bin.js").absolutePath, "config"]
  )
}

Option B — postinstall chmod:

"scripts": {
  "postinstall": "chmod +x node_modules/@react-native-community/cli/build/bin.js || true"
}

After applying the workaround locally, ./gradlew :app:assembleDebug completed cleanly: BUILD SUCCESSFUL in 8m 27s, 189 tasks (Java 17.0.18, AGP 8.7.2, SDK 36).

Other validation that passed locally

  • Root yarn install --immutable
  • yarn typecheck, yarn lint, yarn test --runInBand (376 pass, 1 todo), yarn build
  • Clean iOS Debug simulator build ✅
  • Clean Android assembleDebug ✅ (with rnc-cli workaround)
  • Package alignment good: React/RN 19.1.4 / 0.81.6, @react-native/* 0.81.6, CLI 20.0.0, TS ^5.8.3. react-test-renderer 19.1.4 is fine (peer is react: ^19.1.4). react-native-screens resolves to 4.24.0 within cap.

Approving — would love to see the rnc-cli autolink fix land in this PR rather than as a follow-up, but it's your call.

@lposen lposen merged commit 3343ae3 into feature/SDK-475-update-rn-version-to-0-80 May 15, 2026
11 checks passed
@lposen lposen deleted the update/SDK-476-0-81 branch May 15, 2026 00:22
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.

3 participants