Repository navigation
chore(mobile): bump versions for native release 1.5.187 - #14645
Conversation
- package.json 1.5.186 -> 1.5.187 (triggers the RC and production native builds) - iOS CFBundleShortVersionString 1.1.199 -> 1.1.200 - Android versionName 1.1.535 -> 1.1.536 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Dependency limit exceeded — report not shown. This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report. Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard. Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account. |
) Ships in native release **1.5.187**. It targets `chore/mobile-native-release-1.5.187` (#14645). ## What A `post_install` step in the Podfile patches one line of the SwiftAudioEx pod source, `Sources/SwiftAudioEx/QueueManager.swift`: ```diff - if (self.items.count > 1 && currentIndex >= index) { + if (self.items.count > 0 && currentIndex >= index) { ``` SwiftAudioEx 1.0.0 (our Podfile.lock) and 1.1.0 (RNTP 4.1.2's podspec) only shift the current index for an insert in front of the current item when the queue already has more than one item. With one item, inserting at 0 leaves the index one slot early, and when the track ends the player replays it instead of advancing. Upstream `main` has the `> 0` fix, but it isn't released yet. The step replaces only that exact line. If the file is already patched it does nothing. If the line is missing (for example after a SwiftAudioEx update), it raises and `pod install` fails, so the patch can't be skipped silently. ## Relation to #14649 #14649 is the JS fix, which ships OTA. It avoids the bad insert by appending the later tracks first. When the tapped track is the last one in the list, it uses a temporary placeholder instead. This PR fixes the root cause natively, which covers the last-item case without the placeholder. It also covers any other single-item insert. ## Testing - `RCT_NEW_ARCH_ENABLED=0 bundle exec pod install` prints the patch message, and `Pods/SwiftAudioEx/Sources/SwiftAudioEx/QueueManager.swift:148` now reads `items.count > 0`. - I checked the patch logic on three versions of the file: unpatched gets patched, already patched is left alone, and a changed line raises. - Confirmed the same line is in SwiftAudioEx tag 1.0.0 and in 1.1.0. - Podfile.lock is not changed. The local install showed the known RNTP 4.0.1→4.1.2 / SwiftAudioEx 1.0.0→1.1.0 drift, which I left out. - I haven't rebuilt the native app with this patch. The simulator check of the last-item case was done with the JS fix (#14649). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary Replaces abandoned native libraries ahead of the React Native upgrade. Targets native release **1.5.187**. Stays on RN 0.79 with the old architecture. Rebased on current `main`. **1. `react-native-fs` → `@dr.pogodin/react-native-fs@2.32.1`** - Pinned because 2.33+ uses a codegen EventEmitter spec that the RN 0.79 codegen rejects. - Call sites (`useShareToStory`, `migrateOfflineDataPathSaga`) use a namespace import, since the fork has no default export. The Metro `fs` polyfill alias points at the fork. - **Android:** the fork only compiles its generated module spec with the new architecture on. An `android/build.gradle` hook adds the generated sources when `newArchEnabled` is false, and the module still registers on the bridge. The manual `react-native-fs` include is gone from `settings.gradle`. - **iOS:** `PrivacyInfo.xcprivacy` declares the required-reason APIs the new pod uses (file timestamp `0A2A.1`, disk space `85F4.1`). **2. `react-native-linear-gradient` / `react-native-radial-gradient` → harmony-native `LinearGradient` / `RadialGradient` on `react-native-svg`** - **Rounded corners:** the SVG is clipped to the container's corner radii. - **Angles:** the `angle` prop uses react-native-linear-gradient's own formula, so diagonal gradients on wide boxes (scrubber, tracking bar) keep their colors. - **RadialGradient** renders its children. - **Wallet chart crash:** `react-native-gifted-charts` loads `react-native-linear-gradient` at startup. A Metro shim maps it to our component. - The `SRSRadialGradient` pod and the Android `settings.gradle` include are removed. No code added to `main` since the original commits imports any of the removed libraries or uses `useAngle`, so no new call sites needed converting. ## Scrypt swap dropped The earlier version also replaced `react-native-fast-crypto` with `@noble/hashes` scrypt. That's removed. Under Hermes it took about **11.7 s per derivation** (N=32768, r=8, p=1), against about 90 ms under V8, because Hermes has no JIT. Sign-in runs two derivations, so it would have added more than 20 s to sign-in, and more on phones. `main` already fixes the original problem in #14638: Android uses the native `AudiusScrypt` module, and iOS keeps `react-native-fast-crypto`. This PR doesn't touch `createPrivateKey.ts`, `react-native.config.js` or the `react-native-fast-crypto` dependency. ## Verification - **Typecheck and lint:** `tsc --noEmit -p packages/mobile` passes, and eslint passes on every touched file. - **Pods:** installed with `RCT_NEW_ARCH_ENABLED=0`. No `Pods-AudiusReactNative/*.release.xcconfig` sets `RCT_NEW_ARCH_ENABLED=1`. - **iOS:** a Release build with `.env.prod` succeeds. It runs on an iOS 26.5 simulator, launches to the sign-up screen and logs no JS errors. - **iOS offline-path migration:** I created a file under `Documents/downloads/...` before first launch. On launch, `migrateOfflineDataPathSaga` moved it to `Library/Caches/downloads/...` using the fork's `readDir`, `exists`, `mkdir` and `moveFile`. - **iOS gradients:** I used a temporary, uncommitted panel on the sign-up screen to render: - a 135° rounded `LinearGradient` like the scrubber - a start/end `LinearGradient` with a child, like the tiers header - a `RadialGradient` with a child - a `Skeleton` - `GradientText` - a primary `Button` with a `gradient` - a gifted-charts area chart through the shim All rendered correctly. - **Android:** `assembleProdRelease` (arm64-v8a, signed with the debug keystore) builds. On an API 36 emulator after `pm clear`, logcat shows `Loading JS bundle from "assets://index.android.bundle"`. The app reaches the sign-up and sign-in screens with no fatal or JS errors. The fork's module therefore resolves on the bridge, since `getEnforcing` would throw at import otherwise. **Not verified:** - **Android gradient rendering:** the emulator was starved for CPU during that pass, and every system process hit an ANR. - **Screens that need a signed-in account:** the real scrubber/now playing, rewards tiers and referral copy button weren't checked. I relied on the component-level panel above instead. - **Share-to-story:** not exercised at runtime. ##⚠️ Must ship with a native version bump `@dr.pogodin/react-native-fs` looks up its module with `TurboModuleRegistry.getEnforcing('ReactNativeFs')` at import, and `migrateOfflineDataPathSaga` imports it at startup. If this JS is published as an OTA onto a binary without the module (any current store build), the app crashes at launch. Merge only together with the `packages/mobile/package.json` version bump for the native release that includes it (1.5.187), so that OTAs move to the new binary's history. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#14640) Replaces the unmaintained `react-native-notifications` (Wix) with `@notifee/react-native` 9.1.8 and `@react-native-firebase/messaging` 24.1.1. Rebased from #14506 onto current main (RN 0.79, React Navigation 7, UIScene, target SDK 36). Targets native release **1.5.187**. > [!IMPORTANT] > **Native release only. Do not ship this as an OTA.** It adds and removes native modules. A JS bundle built from this branch would crash on any binary that still has the Wix module, and the reverse is also true. Store builds that predate this change must not receive a CodePush bundle built from it. ## Token compatibility (read this first) **Verdict: compatible, with no server changes needed.** iOS still registers the raw APNs token. The FCM token is used only on Android, which is what Android sent before too. How push works today: - The app POSTs `{deviceToken, deviceType}` to identity `POST /push_notifications/device_token` ([push_notifications.js](https://github.com/AudiusProject/apps/blob/main/packages/identity-service/src/routes/push_notifications.js)). Identity calls SNS `createPlatformEndpoint` against `awsSNSiOSARN` or `awsSNSAndroidARN` and upserts `NotificationDeviceTokens` (the primary key is `deviceToken`). - The SNS platform apps in us-west-1 are `app/APNS/audius_production_ios` and `app/GCM/audius_production_android`, checked read-only with `aws sns list-platform-applications`. **The iOS app is an APNs app, not FCM.** - pedalboard `apps/notifications/src/sns.ts` publishes to the stored `awsARN`, with an `APNS` payload on iOS and a `GCM` payload on Android. What the old draft got wrong: #14506 registered `messaging().getToken()` on iOS, which is an FCM token. SNS rejects that for an APNs platform app, so identity would 500 and new iOS installs would get no pushes. It also used `onNotificationOpenedApp` and `getInitialNotification` for iOS taps. Firebase only reports pushes that carry `gcm.message_id`, and ours come straight from APNs, so iOS taps would never have navigated. What this PR does: - **iOS:** `registerDeviceForRemoteMessages()`, then `getAPNSToken()`, then `.toLowerCase()`. Firebase returns uppercase hex and Wix sent lowercase hex. Without the lowercase step, every existing iOS user would get a second `NotificationDeviceTokens` row and a second SNS endpoint for the same device, and so a duplicate copy of every push. - **Android:** `getToken()`. This is the same FCM token for the same Firebase project (`google-services.json` is unchanged), so existing rows are reused. - `onTokenRefresh` (FCM) is Android-only, so it never overwrites the stored iOS APNs token. Other server-side notes: - **General inbox (pedalboard#93):** the server drops those pushes and never sends them, so there is no silent or data-only push for the client to handle. The push listener fix (pedalboard#103) does not depend on the client. - **Firebase config:** `GoogleService-Info.plist` and the `google-services.json` files are already committed and nothing new was added. `GoogleService-Info.plist` was already in Copy Bundle Resources; this is the first time iOS actually initializes Firebase (`[FIRApp configure]`). No Firebase Analytics pod is added on iOS. ## UIScene interaction Main copied `connectionOptions.notificationResponse` into `launchOptions` so Wix's `getInitialNotification` could read it. Nothing reads it now, so that copy is removed (URL and user-activity forwarding stay). Taps now reach JS like this: - Firebase messaging and notifee both install a `UNUserNotificationCenter` delegate after launch. Whichever installs last forwards anything it does not own to the other one. - Firebase passes non-FCM pushes to the previous delegate, and notifee turns a remote push it receives into a `PRESS` event only when it has no previous delegate. - So `AppDelegate` calls `[[NotifeeCoreUNUserNotificationCenter instance] observe]` first. The chain becomes Firebase → notifee → `PRESS` event. On a cold launch, iOS still delivers the tap to the delegate when the app uses scenes. Notifee queues the event until JS subscribes. `PushNotifications` keeps it in `pendingOpen` until `openInitialNotification()` runs, which happens when navigation is ready, and then navigates once. On iOS, `getInitialNotification` (from Firebase or notifee) is never called, so a tap cannot be handled twice. On Android, cold start uses `getInitialNotification` and warm taps use `onNotificationOpenedApp`. Notifee is not involved on Android. ## What changed - `notifications.ts`: rewritten on top of main's version. It keeps main's `type`/`id` analytics props, the `notification_campaign_id` open report, the Android string-to-type data parsing, and the same `payload.data.data ?? payload.data ?? payload` unwrapping as before. The iOS payload is the APNs userInfo minus `aps`, which is the shape Wix produced. - Removed unused `cancelNotif`, `cancelAll`, `hasPermission` and `lastId`. - `setBadgeCount` (used by `useResetNotificationBadgeCount`) calls `notifee.setBadgeCount` on iOS only, as before. - `requestPermission`: - Android: still `requestNotifications()` from react-native-permissions (`POST_NOTIFICATIONS`). - iOS: `requestPermission()` from Firebase messaging (alert, badge and sound, as Wix did). - `index.js`: a no-op `setBackgroundMessageHandler`. On Android, Firebase starts a headless JS task for every push received in the background, and without a handler it logs a warning. - iOS: - `AppDelegate.mm`: drop Wix, call `[FIRApp configure]`, and set up notifee first. - Podfile: `GoogleUtilities`/`nanopb` modular headers so the Firebase Swift pods link statically. - `pod install` adds Firebase 12.10, RNFBApp/RNFBMessaging 24.1.1 and RNNotifee 9.1.8. `[RNFB] Core Configuration` is added as a build phase, and the privacy manifest picks up the Firebase reasons. - Android: - Remove Wix from `settings.gradle` and `app/build.gradle`. - **Pin the Firebase BoM to 33.16.0** in `android/build.gradle`. RNFB 24 defaults to BoM 34, whose `play-services-measurement` 23.x needs Kotlin 2.2, and the app is on 2.0.21. That pin moves `firebase-messaging` from 23.x to 24.1.2 and `firebase-analytics` to 22.5.0. - Remove RNFB's `default_notification_color` meta-data (`tools:node="remove"`). RNFB defaults the accent to white, and this keeps the system default we had. - `RichPushExtension`: untouched. It reads `media-url` from the APNs payload and is independent of the JS library. - **Notification categories:** none are registered and none are sent, before or after. - **Android channels:** the app never created a channel. Wix didn't create one either, so background pushes landed in FCM's `fcm_fallback_notification_channel`, and they still do (verified below). Users keep their channel settings. - **Foreground pushes:** still not shown on either platform, which matches current behavior. Wix never completed `willPresent` on iOS and never posted in the foreground on Android. - Cherry-pick conflicts: `package-lock.json`, `Podfile.lock` and `PrivacyInfo.xcprivacy` were taken from main and regenerated. `AppDelegate.mm` and `notifications.ts` were redone by hand on main's versions. ## Verification - `npx tsc --noEmit -p packages/mobile`: clean. - eslint and prettier on `notifications.ts`, `notifications.test.ts` and `index.js`: clean, apart from the existing unused `React` import in `index.js`. - New `src/notifications.test.ts`: 9 pass. It covers the iOS lowercase APNs token, the stored-token fallback, cold-start tap held until navigation is ready and handled once, warm taps, Android FCM token, launch notification parsing and the badge being iOS-only. - The mobile jest preset maps `react-native` to `packages/mobile/node_modules`. With the current hoisted install, that file isn't there, so every mobile test (for example `artistNames.test.ts`) fails at setup on main too. I ran this suite with the mapper pointed at the root `node_modules`. - **iOS Release build** (`ENVFILE=.env.prod`, generic iOS Simulator, arm64, `RCT_NEW_ARCH_ENABLED=0`, worktree-local DerivedData): BUILD SUCCEEDED. The release xcconfig has no `RCT_NEW_ARCH_ENABLED=1`. - **Android** `assembleProdRelease -PreactNativeArchitectures=arm64-v8a` with the debug keystore: BUILD SUCCESSFUL. Before the BoM pin it failed with the Kotlin 2.2 metadata error. Device checks were run with a temporary logging build that was not committed. **iOS (new iOS 26.5 simulator, ad-hoc signed so `aps-environment` applies, bundled JS confirmed):** | Check | Result | |---|---| | Permission prompt | Shown, allowed | | APNs token | 160 lowercase hex characters, `os=ios`. No FCM token is used. | | Foreground push (`simctl push`, Follow payload) | Not shown (same as today) | | Background push (Repost, with `media-url`) | Banner shown, badge set to 4 | | Warm tap | One `PRESS`. Payload `{data:{type:'Repost',...},'media-url':...}` matches the Wix shape. | | Cold tap (app killed, CodePush update removed) | Bundled JS loaded. Exactly one open event, delivered after launch through the scene. | **Android (fresh clone of the API 36 AVD, `pm clear`, logcat shows `[CodePush] Loading JS bundle from "assets://index.android.bundle"`):** | Check | Result | |---|---| | FCM token | Fetched (142 characters) | | Push delivery | Simulated as a root `c2dm RECEIVE` broadcast with an FCM notification payload | | Background push | Displayed by FCM on `fcm_fallback_notification_channel`, `color=0x00000000`, `ic_notification` icon | | Foreground push | Not displayed (same as today) | | Cold tap (process killed) | `getInitialNotification` gives one navigate with parsed data (`userIds:[1]`) | | Warm tap | `onNotificationOpenedApp` gives one navigate | No real account was signed in or out, so routing past `navigate(data)` was not exercised. That code path is unchanged. ## Device test checklist (physical devices, before release) The test needs: - A TestFlight or App Store-signed iOS build (production `aps-environment`; the SNS APNs app is production, so dev-signed builds won't receive). - A Play-signed or internal-track Android build. - A test account you can sign in with. - Identity and SNS read access to check rows. 1. **Upgrade in place**, on both platforms. Install the current store build, sign in and enable push. Note the `NotificationDeviceTokens` row for your user. Then install the 1.5.187 build over it and launch. - Expect the same `deviceToken` (iOS lowercase hex, Android the same FCM token). - Expect no new row and no new SNS endpoint. - Expect only one push per event afterwards (a duplicate means the token changed). 2. **Fresh install**: sign in, enable push, and confirm a new row with an SNS endpoint is created. On iOS the token is 64 hex characters on device. 3. Trigger a follow, repost, favorite, DM and comment from another account. For each, check: - App killed: the push shows. Tapping it opens the app and lands on the right screen, once. - App in background: same as above. - App in foreground: no banner (current behavior). - iOS repost/favorite with an image: the rich image still attaches (`RichPushExtension`). 4. **Badge**: let a few pushes accumulate, then open the app. The icon badge clears and `clearNotificationBadges` resets the server count, so the next push shows 1. 5. **Android 13+ permission**: on a fresh install, the `POST_NOTIFICATIONS` prompt appears when enabling push, and denying it is respected. 6. **Android channel**: in App info → Notifications, the channel is still the system "Miscellaneous"/default one, and a setting changed there before the upgrade survives it. 7. **Disable push** in settings: the deregister call succeeds and the row and endpoint are removed. 8. **General inbox**: a DM in a chat filed as General produces no push, and Priority still does. 9. Campaign push (with `notification_campaign_id`): opening it records a push open. ## Open risks - **Android headless JS per background push.** Firebase's receiver starts a headless JS task for every push that arrives while the app is backgrounded. Wix did not. This boots JS in the background more often. Watch battery and ANR reports. On the emulator, one delivery while JS was booting took about 70s in `Service took too long to process intent`, which I attribute to the slow emulator, but please watch it on device. - **Delegate order depends on notifee internals** (`NotifeeCoreUNUserNotificationCenter observe`). It is a compile-time import, so a rename fails the build rather than silently breaking taps. Re-check it on notifee upgrades. - The **Firebase BoM pin to 33.16** should be removed when the app moves to Kotlin 2.2 (RN 0.81+ ladder). - RNFB auto-registers for remote notifications at launch on iOS. That doesn't show a prompt. Supersedes #14506. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Phase 1 of the React Native upgrade: 0.79.5 → 0.81.6 with the old architecture still on. **Base: `chore/mobile-native-release-1.5.188` (#14654).** Rebased onto it after 1.5.187 (#14645, which squashed #14627, #14640 and #14650) merged to main; the two lib-swap commits are gone from this branch. Merge #14647 and #14651 into this branch first, then this into #14654, then #14654 into main as one push (see #14654 for the full order). ## Rebase onto 1.5.187 (2026-10-08) - `patches/react-native+0.79.5.patch` (the ExceptionsManager Hermes fix from #14643) is renamed to `react-native+0.81.6.patch`. The anchors are unchanged in 0.81.6, and `scripts/patch-package.sh` applies it with `--error-on-fail` during `npm install` (checked: `getErrorStackSafe` is in the installed `ExceptionsManager.js`). - notifee and Firebase from #14640 are kept as they are: `@notifee/react-native` 9.1.8 is the latest release and `@react-native-firebase/app`/`messaging` 24.1.1 build on 0.81.6 on the old arch (both declare `react-native: *`). No bump needed. - The Firebase Android BoM stays pinned to 33.16.0. This branch moves Kotlin to 2.1.20, and BoM 34 needs 2.2, so the pin still applies; the comment now says so. - The UIScene and notifee lines in `AppDelegate.mm` (#14626, #14640) are untouched by this branch. - `package-lock.json` and `Podfile.lock` were regenerated (`npm install`, then `RCT_NEW_ARCH_ENABLED=0 bundle exec pod install`); the release xcconfig has no `RCT_NEW_ARCH_ENABLED=1`. The SwiftAudioEx post_install patch (#14650) still applies. **Needs a native release (1.5.188).** Don't OTA this JS onto older binaries. Old architecture stays on: Android `newArchEnabled=false`, iOS `RCTNewArchEnabled=false`, pods installed with `RCT_NEW_ARCH_ENABLED=0`. Two commits, one per step. Each step builds on iOS and Android: 1. 0.79.5 → 0.80.3 2. 0.80.3 → 0.81.6 (0.81.6 is the latest 0.81 patch on npm) ## Version bumps | Package | From | To | Why | |---|---|---|---| | react-native | 0.79.5 | 0.81.6 | the upgrade | | `@react-native/*` (babel-preset, eslint-config, metro-config, metro-babel-transformer, typescript-config) | 0.79.5 | 0.81.6 | must match RN | | `@react-native-community/cli`, `cli-platform-android`, `cli-platform-ios` | 18.0.0 | 20.1.3 | CLI line for 0.81; the platform packages were left at 18 on the old ladder branch | | react, react-dom, react-test-renderer (whole monorepo, root `overrides` too) | 19.0.0 | **19.1.4** | RN's bundled renderer throws at startup unless `react` is **exactly** its version: 19.1.0 for 0.80.3, 19.1.4 for 0.81.6. The old ladder branch used 19.1.8, which would throw "Incompatible React versions" on launch. | | @types/react / @types/react-dom | 19.0.0 | 19.1.17 / 19.1.11 | match React 19.1 | | react-native-gesture-handler | 2.25.0 | 2.28.0 | 2.28 is the first 2.x with official 0.81 support (2.25's table stops at 0.79). Stays on 2.x; v3 drops the old architecture. | | @amplitude/analytics-react-native | 1.4.11 | 1.4.14 | Kotlin 2.1 (RN 0.80+) turns the deprecated `toUpperCase(Locale)` in 1.4.11 into a compile error | | tiktok-opensdk-react-native | ^0.10.7 | 0.10.7 (pinned) | it now carries a patch. 0.10.9 fixes the Android signature, but drops the `handleOpenURL`/`handleUserActivity` declarations that SceneDelegate imports | Patches added (`patches/`): - `react-native-track-player+4.1.2.patch`: Kotlin 2.1 rejects `Arguments.fromBundle(Bundle?)`. Now resolves `null` when there is no item. 4.1.2 is the last 4.x and has no fixed release. - `tiktok-opensdk-react-native+0.10.7.patch`: `onNewIntent(intent: Intent)` (RN 0.80 made `ActivityEventListener` non-null) and `reactApplicationContext.currentActivity`. Checked against 0.81 on the old architecture and left alone: Reanimated 3.19.5 (the official table lists 3.19.x for 0.78–0.81 on Paper; Reanimated 4 is out of scope), track-player 4.1.2 (patched above), collapsible-tab-view 8.0.1 (JS only), screens 4.18.0 (0.81 support since 4.14; `react-native-screens+4.18.0.patch` still applies; 4.25+ drops the old arch), pager-view 6.7.1 (7+ drops the old arch), video 6.18.0, svg 15.15.0 (0.81 support since 15.12.1), google-cast 4.6.2 (5.x is new-arch only), notifications 5.1.0, code-push 12.3.2 (README lists 0.77–0.86; 13.x needs a new OTA history), bootsplash 6.3.11, safe-area-context 5.6.2, keyboard-controller 1.19.0, flash-list 1.8.3, datetimepicker 8.3.0 (builds against 0.81.6). ## Template changes (rn-diff-purge 0.79.5 → 0.81.6) - Android: Kotlin 2.0.21 → 2.1.20, Gradle 8.13 → 8.14.3, new `gradlew`/`gradlew.bat`/wrapper jar, `MainApplication` uses `loadReactNative(this)` in place of `SoLoader.init` plus `load()`, and `edgeToEdgeEnabled=false` is added as in the template. The app already draws edge-to-edge through react-native-bars and the SDK 36 target, so this flag changes nothing. - AGP comes from RN: 8.8 → 8.11.0, which supports compileSdk 36, so `android.suppressUnsupportedCompileSdk=36` is removed. - `settings.gradle` resolves `@react-native/gradle-plugin` through `require.resolve` from `react-native`, not a hard-coded hoisted path. With this lockfile npm nests it under `node_modules/react-native/node_modules`. - Kept: `newArchEnabled=false`, the `AudiusScrypt` module (`ScryptPackage` is still registered), the debug manifest (it adds `SYSTEM_ALERT_WINDOW`), and `android:enableOnBackInvokedCallback="false"`. - **Back handling:** since 0.80, `ReactActivity` registers an `OnBackPressedCallback` when targetSdk ≥ 36, which calls `onBackPressed()` → JS `BackHandler`. Our `invokeDefaultOnBackPressed` override (`moveTaskToBack`) still runs. The manifest opt-out is kept as asked and can probably go in a later release. - iOS: no template change between 0.79.5 and 0.81.6. `Info.plist` and `RichPushExtension/Info.plist` now set `RCTNewArchEnabled=false`, which RN 0.80+ reads **at runtime**; a missing key means new arch. `pod install` writes the key and re-sorts the plist each time, so the sorted version is committed. ## AppDelegate / UIScene No code change needed. `RCTAppDelegate` is marked deprecated in 0.81 in favour of `RCTReactNativeFactory`, so there is a `-Wdeprecated-declarations` warning, but every API we use is unchanged: `automaticallyLoadReactNativeWindow`, `rootViewFactory`, `createRootViewController`, `setRootView:toRootViewController:`, `customizeRootView:`, `bundleURL`, and `dependencyProvider`. `didFinishLaunching` still creates the factory and skips the window. Moving to `RCTReactNativeFactory` can wait for the 0.82+ phase. Verified on a Release build: cold launch, a deep link while killed, and a deep link while backgrounded, on iOS 26.5 and iOS 27. iOS 27 needs UIScene and showed no launch crash. ## Web / React 19.1 - Typecheck: web, common and harmony are clean, and so is mobile. - `vite build` (prod env): succeeds. - web vitest: 178 passed, 9 skipped. `TrackTile › Public Premium (non-owner)` timed out once while the machine was under heavy load, then passed 3 out of 3 when run alone. ## Verification matrix (before the rebase; see the bottom for the rebased stack) | | iOS 26.5 sim (Release) | iOS 27 sim (Release) | Android API 36 emu (prodRelease, arm64) | |---|---|---|---| | Build | ✅ Xcode 27, `generic/platform=iOS Simulator` | same binary | ✅ debug keystore | | Old arch at runtime | ✅ JS thread `com.facebook.react.JavaScript` | – | ✅ `ReactRootView` + "Legacy Architecture" warning | | Launch past splash | ✅ | ✅ | ✅ `assets://index.android.bundle` | | Sign-up / sign-in screens | (signed in) | ✅ | ✅ including Create Password | | Signed-in feed, scroll | ✅ | – | – | | Playback + now playing drawer (open, drag closed) | ✅ | – | – | | Background → foreground while playing | ✅ audio kept going (0:09 → 0:41) | – | – | | Search | ✅ | – | – | | Profile: collapsible header + tab swipe | ✅ | – | – | | Deep link, warm | ✅ `audius://audius` | ✅ link delivered | – | | Deep link, cold | ✅ `audius://deadmau5` | ✅ (signed out → sign-on) | – | | Hardware Back | – | – | ✅ pops Create Password; at root backgrounds the app without killing it | | Sign-on footer above nav bar | – | – | ✅ | | Red JS errors | none, apart from a recurring `JSON Parse error: Unexpected character: <` (not yet traced) | none | none | The CodePush folder was moved aside or cleared before every cold launch, so all results above are from the bundled JS. ## Still needs a real device - background audio with the screen locked for more than 2 minutes - lock-screen and notification controls - Chromecast - push notifications ## Notes - A Release build that downloads a production OTA built for 1.5.186 or 1.5.187 runs a 0.79 bundle on a 0.81 binary. 1.5.188 ships with its own package.json version (#14654) so it never receives those OTAs. - The Hermes `ExceptionsManager` fix now applies through patch-package (#14643), renamed for 0.81.6 above. ## Verification of the rebased stack (2026-10-08) Built from a local, unpushed integration branch: #14652's tip (which contains #14647) merged with #14651, on top of #14654. | Check | Result | |---|---| | `npx tsc --noEmit -p packages/mobile` | pass | | eslint on the touched files / `turbo run verify` lint | pass (1 existing warning in `HostRemixContestDrawer.tsx`) | | `cd packages/mobile && npm test` | 9 suites, 34 tests pass | | iOS Release, `generic/platform=iOS Simulator`, arm64, `ENVFILE=.env.prod` | builds; Info.plist 1.1.201, `RCTNewArchEnabled=false`; bundle carries 1.5.188 | | Android `assembleProdRelease`, arm64-v8a, debug keystore | builds; versionName 1.1.537 | | iOS 26.5 sim, installed over the signed-in app, CodePush moved aside | launch to feed; JS thread `com.facebook.react.JavaScript` (old arch) | | Playback from the 2nd feed track | plays; play bar tracker moves | | Auto-advance | seek to 2:43/2:45 on track 2, advanced to track 3 | | Now playing drawer | opens, scrubber advances, tap-to-seek works | | Profile tabs | swipe Tracks → Albums, tap Reposts | | notifee/RNFB APNs token | a temporary console log (not committed, rebuilt without it afterwards) printed an 80-byte lowercase APNs token at startup | | Android 16 emulator, `pm clear` | `Loading JS bundle from "assets://index.android.bundle"`, "Legacy Architecture" warning, sign-up and sign-in screens render | | Android hardware Back | **not verified**: the emulator's system_server was killed by its watchdog three times under host load, so Back never got a clean run | | JS errors on iOS | only `Could not cache profile images` (content node timeout) | 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Version bump for native release 1.5.187. Merging it starts the RC and production native builds.
packages/mobile/package.json: 1.5.186 → 1.5.187CFBundleShortVersionString: 1.1.199 → 1.1.200versionName: 1.1.535 → 1.1.5361.5.187 contains:
@dr.pogodin/react-native-fsand the react-native-svg gradients@react-native-firebase/messagingMerge order
TurboModuleRegistry.getEnforcing('ReactNativeFs')at import, so they would crash. With one push that also changes the version, the version check skips the OTA and starts the native builds instead. After that, OTAs route to1.5.187histories.🤖 Generated with Claude Code