Compare commits

..
Author SHA1 Message Date
Nicola Corti 2f5a74f68e Unblock run_fantom_tests by pinning react-native-android to v18.0 2025-09-11 12:20:41 +01:00
Vitali Zaidman cda0ad8c5f Update debugger-frontend from e87564a...5a792db (#53714)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53714

Changelog: [Internal] - Update `react-native/debugger-frontend` from e87564a...5a792db

Resyncs `react-native/debugger-frontend` from GitHub - see `rn-chrome-devtools-frontend` [changelog](https://github.com/facebook/react-native-devtools-frontend/compare/e87564a24cf233c60aaebee8c418ec85724f7214...5a792db1225adda206313e9bf751198a1ca7851a).

### Changelog

| Commit | Author | Date/Time | Subject |
| ------ | ------ | --------- | ------- |
| [5a792db12](https://github.com/facebook/react-native-devtools-frontend/commit/5a792db12) | Vitali Zaidman (vzaidman@gmail.com) | 2025-09-01T11:06:46+01:00 | [track clicks on script links (#204)](https://github.com/facebook/react-native-devtools-frontend/commit/5a792db12) |
| [7edec7c48](https://github.com/facebook/react-native-devtools-frontend/commit/7edec7c48) | Vitali Zaidman (vzaidman@gmail.com) | 2025-08-28T10:24:49+01:00 | [track the duration between user setting a breakpoint and the breakpoint being painted (#201)](https://github.com/facebook/react-native-devtools-frontend/commit/7edec7c48) |
| [273f02681](https://github.com/facebook/react-native-devtools-frontend/commit/273f02681) | Ruslan Lesiutin (28902667+hoxyq@users.noreply.github.com) | 2025-08-27T19:33:26+01:00 | [Revert "Add landingView query param enabling view focus on launch (#197)" (#202)](https://github.com/facebook/react-native-devtools-frontend/commit/273f02681) |
| [1e19c4454](https://github.com/facebook/react-native-devtools-frontend/commit/1e19c4454) | Vitali Zaidman (vzaidman@gmail.com) | 2025-08-21T16:23:44+01:00 | [Fixed Protocol Manager displaying events with no params as "(pending)". (#200)](https://github.com/facebook/react-native-devtools-frontend/commit/1e19c4454) |

Reviewed By: robhogan

Differential Revision: D82117068

fbshipit-source-id: 4112be5e8a4f643dffc46e7956c821041dad3b26
2025-09-11 03:49:25 -07:00
Riccardo Cipolleschi dab8a45623 cipolleschi/fix rctnetworking not building (#53713)
Summary:
Fix Cocoapods builds with static libraries and dynamic frameworks

## Changelog:
[Internal] -

Pull Request resolved: https://github.com/facebook/react-native/pull/53713

Test Plan: Tested locally on RNTester

Reviewed By: cortinico

Differential Revision: D82118127

Pulled By: cipolleschi

fbshipit-source-id: 73736c2382be5f6b0770bb7154780e6dcc4aca1c
2025-09-10 12:14:14 -07:00
generatedunixname537391475639613 40c60adacf xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java (#53704)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53704

Reviewed By: cortinico

Differential Revision: D82098400

fbshipit-source-id: e692b8e2bad976805657c2f406831c346198554f
2025-09-10 07:23:21 -07:00
Riccardo Cipolleschi a7cd3cc08f Make codegen generate a Package.swift file for Codegen'd target (#53619)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53619

With this change, we are making Codegen generate a Package.swift file so that we can integrate the `ReactCodegen` and the `ReactAppDependencyProvider` in apps only using SwiftPM

## Changelog
[iOS][Added] - Make codegen generate PAckage.swift file for the codegen targets

Reviewed By: cortinico

Differential Revision: D81769543

fbshipit-source-id: 1f1a1b9f41126e142931d5eda6e75109a69f828c
2025-09-10 05:25:54 -07:00
Riccardo Cipolleschi 87f8e85b7f Move generated code to ReactCodegen and ReactappDependencyProvider folder (#53618)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53618

This change makes sure that we generate the codegen files in the ReactCodegen and ReactAppDependencyProvider folder.

This is necessary as Swift PM needs the source code of packages to be grouped in folders that are children of where the Package.swift is located.

This is not a breaking change, because Cocoapods has been updated accordingly, import/include paths are not changed and the folder layout should not be accessed by anybody directly

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81769522

fbshipit-source-id: 7c70f96a9aa503c4faaf173b94c8ee0e326094a1
2025-09-10 05:25:54 -07:00
Phil Pluckthun f6f5ea0b2e Remove outdated artifacts codegen early return (#53690)
Summary:
Follow-up to https://github.com/facebook/react-native/issues/53503 for a regression

When no React Native module is present this bail condition stops us from generating the artifacts podspec that's needed to complete build.

## Changelog:

[IOS] [FIXED] - Fix regression that skips artifacts code generation

Pull Request resolved: https://github.com/facebook/react-native/pull/53690

Test Plan:
- Create an app **without** any React Native modules, run `pod install`; without this fix the podspec will be missing and the build will fail
  - With expo this can be reproduced using `create-expo-app --template blank-typescript@next` on `react-native@0.81.2`
  - With the community CLI this can be reproduced using `npx react-native-community/cli@latest init test --skip-install --version 0.81.2` and uninstalling `react-native-safe-area-context`

Reviewed By: javache

Differential Revision: D82103491

Pulled By: cipolleschi

fbshipit-source-id: 3d9619b5a935ca920220824b3963a9a107f926ca
2025-09-10 05:24:28 -07:00
Riccardo Cipolleschi 6c49572ee4 Make sure we don't run RN CI on forks (#53707)
Summary:
We had reports from the Community of the RN CI running on forks and causing high costs and bills for them
This change should make sure that the most impactful jobs only runs on the React Native CI and not on forks.

## Changelog:
[Internal] -

Pull Request resolved: https://github.com/facebook/react-native/pull/53707

Test Plan: GHA

Reviewed By: cortinico

Differential Revision: D82107313

Pulled By: cipolleschi

fbshipit-source-id: ff7f418344975e7bb8306a6356d774c26bea3db1
2025-09-10 04:49:14 -07:00
Rubén Norte 529f55c8c9 Implement performance.timeOrigin (#53660)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53660

Changelog: [internal]

(This is internal because these APIs aren't enabled in OSS yet)

Implements `performance.timeOrigin` to allow converting timestamps from `performance.now()` to be based on the Unix epoch.

This implementation isn't fully spec-compliant to align with the current implementation of `performance.now()`, where the base of the clock is system boot time instead of app startup / navigation time.

Reviewed By: huntie

Differential Revision: D82016724

fbshipit-source-id: e3a066721cecf41e2fd963beb94a0a2f1c5d6493
2025-09-10 04:48:55 -07:00
generatedunixname537391475639613 481fb612a2 xplat/js/react-native-github/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareGflagsTaskTest.kt (#53702)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53702

Reviewed By: cortinico

Differential Revision: D82093601

fbshipit-source-id: 133936f59d155fa1d68358abe4015c7b7b1613a6
2025-09-10 04:41:29 -07:00
Oskar Kwaśniewski 3ce6a05aac fix: add conditional checks for facebook/react-native repo for nightly (#53700)
Summary:
This PR adds additional checks to run nightly jobs only on the main repo.

I noticed pretty heavy usage on my fork of React Native:

<img width="951" height="179" alt="Screenshot 2025-09-10 at 11 47 29" src="https://github.com/user-attachments/assets/91cb9e4a-8658-42bd-bbfe-ffba01b0b3b3" />

I also noticed a typo in this file with output instead of outputs

## Changelog:

[INTERNAL] [FIXED] - add conditional checks for facebook/react-native repo for nightly workflow

Pull Request resolved: https://github.com/facebook/react-native/pull/53700

Test Plan: Check if the syntax is correct.

Reviewed By: cortinico

Differential Revision: D82104958

Pulled By: cipolleschi

fbshipit-source-id: fc2e6e0299345ebd115c7a574a5a8161f2b0ca5c
2025-09-10 03:57:54 -07:00
Jakub Piasecki 813b9441ca Read Hermes V1 opt-in flag from the app's properties (#53665)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53665

Changelog: [ANDROID][FIXED] - Read the Hermes V1 opt-in flag from the apps properties when building from source

Reviewed By: cortinico

Differential Revision: D82018545

fbshipit-source-id: f3c6fdbac190f47b6bf6836105d9e0909d8b86ba
2025-09-10 00:51:41 -07:00
Zeya Peng cf5040b4f8 fix array type parsing in DynamicEventPayload::extractValue (#53689)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53689

## Changelog:

[General] [Fixed] - fix array type parsing in DynamicEventPayload::extractValue

When unwrapping event mapping like `e.nativeEvent.touches[0].locationX` e.g. for Animated.event like below,

```
onTouchMove={Animated.event(
  [
    {
      nativeEvent: {
        touches: {
          0: {locationX: animatedValue},
        },
      },
    },
  ],
  {useNativeDriver: true},
)}
```
here it'll throw exception `terminating due to uncaught exception of type folly::TypeError: TypeError: expected dynamic type 'object', but had type 'array'` when getting into folly dynamic array, because array index in the event path is string instead of integer

Reviewed By: rozele

Differential Revision: D82050538

fbshipit-source-id: ed25c8917b90190c995d1fcd6d60af207e72e270
2025-09-09 21:12:26 -07:00
Luna Wei 019a553ea4 Remove enable_eager_alternate_state_node_cleanup param (#53693)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53693

Changelog: [Internal] - Remove usage of `enableEagerAlternateStateNodeCleanup`  as it is default true now

Reviewed By: yungsters

Differential Revision: D81962955

fbshipit-source-id: 80b0d9321b1162dd79d052b05acb3dc9459e37d2
2025-09-09 18:46:39 -07:00
generatedunixname89002005287564 2ae5a74f06 Fix CQS signal modernize-use-using in xplat/js/react-native-github/packages (#53661)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53661

Reviewed By: javache

Differential Revision: D81764229

fbshipit-source-id: 617716ddb5cf17d41a4927c3a6cce6074278d8b0
2025-09-09 11:37:24 -07:00
generatedunixname537391475639613 3d4a4caac8 xplat/js/react-native-github/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt (#53614)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53614

Reviewed By: javache

Differential Revision: D81764947

fbshipit-source-id: de19d7d89f3a7e19285928f9541b0b47b503d160
2025-09-09 11:34:37 -07:00
Alex Hunt cdc4a8ead4 Wire up background tracing and actions in Perf Monitor (#53460)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53460

Completes the first pass of adding background performance trace controls in the V2 Perf Monitor UI.

Key changes:
- Initiates background trace on `PerfMonitorOverlayManager::init`.
- Wires up background trace recording states in button dialog, and connects `pauseAndAnalyzeBackgroundTrace` and `resumeBackgroundTrace` actions.
- Moves UI manager/view classes into `perfmonitor` subpackage.
- Fixes `responsivenessScore` determination/UI coloring.
- Adds tooltip UI to the overlay view.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D80807554

fbshipit-source-id: 53360c2d454adfbba40fd795d400b28d90ff9e61
2025-09-09 10:31:04 -07:00
generatedunixname537391475639613 226d2ba160 xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.kt (#53656)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53656

Reviewed By: cortinico

Differential Revision: D82005918

fbshipit-source-id: 5b0728e68fff865e8a9271c0dfc0a3cc19baa54c
2025-09-09 08:13:12 -07:00
Rubén Norte a16c6c9477 Add feature flag to enable Web Performance APIs by default (#53547)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53547

Changelog: [internal]

This creates a new feature flag to enable the modern Web performance APIs in RN by default. It's disabled by default so it shouldn't have any effect at the moment.

Reviewed By: rshest

Differential Revision: D80811430

fbshipit-source-id: 47d5fd12ac8809aa3c5ad37cdd31c0d9e3ed5912
2025-09-09 08:07:31 -07:00
Vitali Zaidman 59b8974d3c changelog/v0.80.0-rc.1 (#53662)
Summary:
Changelog: [Internal]

Pull Request resolved: https://github.com/facebook/react-native/pull/53662

Reviewed By: fabriziocucci

Differential Revision: D82020526

Pulled By: vzaidman

fbshipit-source-id: 43eb1d038f71dbeb30bd1bf4a94779a9fad56215
2025-09-09 07:46:35 -07:00
generatedunixname537391475639613 2c30215bc7 xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/core/tests/TestComponent.h (#53658)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53658

Reviewed By: javache

Differential Revision: D81904578

fbshipit-source-id: 03725446586cc206690995f7d2d274c0b1249abe
2025-09-09 04:57:44 -07:00
generatedunixname537391475639613 f568c9b953 xplat/js/react-native-github/packages/gradle-plugin/shared-testutil/src/main/kotlin/com/facebook/react/tests/OsRule.kt (#53655)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53655

Reviewed By: cortinico

Differential Revision: D82008708

fbshipit-source-id: 9ba77512a5e6e7749981726d739d88df287a63d3
2025-09-09 03:42:58 -07:00
25harsh 968909488a fix(iOS): Fix RCTDeviceInfo crash when application.delegate.window is nil (#53645)
Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

Fixes a crash in `RCTDeviceInfo.interfaceOrientationDidChange` when `application.delegate.window` is nil. This crash affects multiple modern iOS app architectures where the traditional window property may not be set:

- **SwiftUI apps using `main`** instead of traditional AppDelegate
- **Brownfield React Native integrations** where the host app manages windows
- **Scene-based lifecycle apps** (iOS 13+) using SceneDelegate
- **Custom window management** setups

**The Problem:**
```
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[MyApp.AppDelegate window]: unrecognized selector sent to instance'
```

This occurs when trying to access `.frame` on a nil window object during orientation changes. Modern iOS development patterns don't always require setting `application.delegate.window`, but React Native's RCTDeviceInfo assumes this property exists.

**The Solution:**
Replace direct `application.delegate.window` access with `RCTKeyWindow()` and add nil-safe fallback:

```objc
// Before (crashes in modern apps)
BOOL isRunningInFullScreen =
    CGRectEqualToRect(application.delegate.window.frame, application.delegate.window.screen.bounds);

// After (safe for all app configurations)
UIWindow *delegateWindow = RCTKeyWindow();
BOOL isRunningInFullScreen = delegateWindow ?
    CGRectEqualToRect(delegateWindow.frame, delegateWindow.screen.bounds) : YES;
```

This approach:
- Uses `RCTKeyWindow()` pattern already established elsewhere in RCTDeviceInfo
- Provides safe fallback defaulting to fullscreen when window state is unknown
- Maintains existing multitasking detection behavior (Split View, Slide Over)
- Is backward compatible with traditional React Native apps

## Changelog:
<!-- Help reviewers and the release process by writing your own changelog entry.
Pick one each for the category and type tags:
[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[IOS][FIXED] - Fix RCTDeviceInfo crash when application.delegate.window is nil in modern iOS app architectures

Pull Request resolved: https://github.com/facebook/react-native/pull/53645

Test Plan:
### Manual Testing

**1. SwiftUI main App Test:**
```bash
# Created SwiftUI app with main lifecycle
# Integrated React Native component
# Result: No crash during orientation changes, fullscreen detection works
 PASS: Orientation changes handled safely
 PASS: Multitasking detection stable
```

**2. Traditional React Native App:**
```bash
# Tested with standard RN template app
# Verified existing behavior unchanged
 PASS: Existing functionality preserved
 PASS: No regressions in dimension reporting
```

**3. Brownfield Integration:**
```bash
# Integrated RN in existing iOS app without window property
# Triggered orientation changes and multitasking transitions
 PASS: No crashes during orientation events
 PASS: Split View and Slide Over work correctly
```

**4. Scene-based Lifecycle App:**
```bash
# Created app using SceneDelegate for window management
# Tested orientation and multitasking scenarios
 PASS: Proper handling when SceneDelegate manages windows
 PASS: No crashes during app lifecycle transitions
```

### Edge Case Testing

**RCTKeyWindow() Returns Nil:**
- Confirmed defaults to `YES` (fullscreen)
- No crashes when no key window available
- Multitasking detection remains stable

**Multiple Window Scenarios:**
- Tested with iPad multiple windows
- Uses correct key window for measurements
- Proper behavior in complex window hierarchies

**Orientation During Transitions:**
- App backgrounding/foregrounding during orientation
- Multitasking mode changes during rotation
- No crashes or inconsistent states

### Automated Testing

```bash
# All existing tests pass
yarn test
 RCTDeviceInfoTests pass

# Code style compliance
yarn lint
 Follows React Native Objective-C guidelines
```

### Impact Verification

**Before Fix:**
- Crash in SwiftUI apps using main
- Crash in Scene-based lifecycle apps
- Crash in brownfield integrations

**After Fix:**
- All app architectures work safely
- Multitasking detection preserved
- Backward compatibility maintained
- No performance impact

Rollback Plan:

Reviewed By: javache

Differential Revision: D81931754

Pulled By: cipolleschi

fbshipit-source-id: c3ea1a2922b1d48ca6bc1fc32861b490322fd254
2025-09-09 02:23:52 -07:00
Alex Hunt e7ce4ff0bf Move NetworkReporter out of jsinspector-modern (#53484)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53484

Refactor to better organise network event reporting features.

- Introduce new `ReactCommon/react/networking` package, containing `NetworkReporter` class (outer-most interface with each platform).
    - Move `ReactCommon/performance/timeline` dependency to this level, removing jsinspector→performance dependency.
- Simplifies the remaining `NetworkHandler` in `jsinspector-modern/network` — which now is only focused on CDP network reporting.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D81129562

fbshipit-source-id: 6c36045e872b0fd9510d0fa3e98acb0969e74d72
2025-09-08 13:35:23 -07:00
Riccardo Cipolleschi 49be01add1 Move headers from .h to .mm file (#53617)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53617

In the RCTAppDelegate.h file there are a couple of headers that are not used and that can be either removed or moved to the .mm file.
This reduce the coupling between the AppDelegate library and React Core and allow us to reduce the size of the exported headers in the umbrella header.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81769485

fbshipit-source-id: b811dde0331e8a668618e0c8eb250fd81bf48545
2025-09-08 10:27:24 -07:00
Nicola Corti 13120f630d Remove unnecessary extra quote on hermesVersionProvider (#53641)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53641

This extra quote is causing the build on the 0.82-stable to fail. The reason is that the Path for the `.hermesversion` file is composed wrongly so we attempt to build hermes from the `main` branch.

Changelog:
[Internal] [Changed] -

Created from CodeHub with https://fburl.com/edit-in-codehub

Reviewed By: j-piasecki, vzaidman

Differential Revision: D81925624

fbshipit-source-id: 700f9d44b6c7efdb845232dad8ca7c2e3136385d
2025-09-08 09:09:23 -07:00
Rick Hanlon d0140ce53b enable opt-in for enableDefaultTransitionIndicator (#34373)
Summary:
So we can test the feature.

DiffTrain build for [3168e08f8389d258de9eb7c8d19b9d44a0f250f2](https://github.com/facebook/react/commit/3168e08f8389d258de9eb7c8d19b9d44a0f250f2)

Reviewed By: kassens

Differential Revision: D81599263

fbshipit-source-id: a33ca01250206a2a35350f7fad09e43071522df7
2025-09-08 08:43:40 -07:00
Jakub Piasecki d0fb33822d Check value of the Hermes V1 flag instead of whether it's defined (#53637)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53637

Changelog: [ANDROID][FIXED] - Check for the value of the HERMES_V1_ENABLED flag instead of whether it's defined

Reviewed By: cortinico

Differential Revision: D81920483

fbshipit-source-id: 550ae9fd27f666affe102b1c5c3f51bde7b5923e
2025-09-08 07:16:48 -07:00
Rob Hogan 2152180fa0 Minor bump memfs dev dependency (#53628)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53628

Bump the `memfs` dependency used in tests to the latest minor - there have been a considerable number of updates since 4.7 including support for various newer (and some old) Node fs APIs: https://github.com/streamich/memfs/blob/master/CHANGELOG.md

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D81879137

fbshipit-source-id: e75946dac100809cb39c88971fd6ed397dc9f49e
2025-09-08 06:54:09 -07:00
Ramanpreet Nara e7aeea26bd Deprecate legacy javascript apis (#53630)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53630

These JavaScript apis were a part of react native's legacy architecture. Let's deprecate them, so that we can eventually remove them in the future.

Changelog: [General][Deprecated] - Deprecate legacy javascript react native apis

Reviewed By: cortinico

Differential Revision: D81795732

fbshipit-source-id: 0a2bd142fa7e08c1f3daaa437ee127a2156e045b
2025-09-08 04:30:21 -07:00
Bartosz Kaszubowski c04248dc5c chore: Add Bluesky badge to README (#53616)
Summary:
Add Bluesky badge to README.

## Changelog:

[INTERNAL][ADDED] Add Bluesky badge to README

Pull Request resolved: https://github.com/facebook/react-native/pull/53616

Test Plan:
The updated README has been checked out on the PR branch.

## Preview:

<img width="1880" height="746" alt="Screenshot 2025-09-05 at 13 00 34" src="https://github.com/user-attachments/assets/dc1dfa9c-9e08-449d-82b8-dcb92ae92268" />

Reviewed By: cipolleschi

Differential Revision: D81909921

Pulled By: cortinico

fbshipit-source-id: b5fa79f152f126944bc1c31c8fbb86889f0f25db
2025-09-08 03:48:46 -07:00
121 changed files with 2012 additions and 802 deletions
+1
View File
@@ -19,6 +19,7 @@ on:
jobs:
create_release:
if: github.repository == 'facebook/react-native'
runs-on: ubuntu-latest
steps:
- name: Checkout
+6 -3
View File
@@ -23,6 +23,7 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -50,8 +51,8 @@ jobs:
- name: Build HermesC Apple
uses: ./.github/actions/build-hermesc-apple
with:
hermes-version: ${{ needs.prepare_hermes_workspace.output.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.output.react-native-version }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_apple_slices_hermes:
runs-on: macos-14
@@ -75,7 +76,7 @@ jobs:
uses: ./.github/actions/build-apple-slices-hermes
with:
flavor: ${{ matrix.flavor }}
slice: ${{ matrix.slice}}
slice: ${{ matrix.slice }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
@@ -101,6 +102,7 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
@@ -145,6 +147,7 @@ jobs:
build_android:
runs-on: 8-core-ubuntu
if: github.repository == 'facebook/react-native'
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
@@ -9,6 +9,7 @@ on:
jobs:
publish_bumped_packages:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
steps:
+2
View File
@@ -21,6 +21,7 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -98,6 +99,7 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
+1
View File
@@ -9,6 +9,7 @@ on:
jobs:
rerun:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: rerun ${{ inputs.run_id }}
env:
+7 -1
View File
@@ -11,6 +11,7 @@ on:
jobs:
set_release_type:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
env:
@@ -34,6 +35,7 @@ jobs:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
@@ -112,6 +114,7 @@ jobs:
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
@@ -379,7 +382,8 @@ jobs:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
# Version is pinned to v18.0 to unblock `run_fantom_tests` - see https://github.com/react-native-community/docker-android/pull/242#issuecomment-3280029122
image: reactnativecommunity/react-native-android:v18.0
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
@@ -594,6 +598,7 @@ jobs:
test_js:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
strategy:
fail-fast: false
matrix:
@@ -608,6 +613,7 @@ jobs:
lint:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@ -27,6 +27,7 @@ on:
jobs:
validate-dotslash-artifacts:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout repository
uses: actions/checkout@v4
+32
View File
@@ -1,5 +1,37 @@
# Changelog
## v0.82.0-rc.1
### Added
#### Android specific
- **Hermes V1:** Added opt-in to use the new Hermes ([3e9990f860](https://github.com/facebook/react-native/commit/3e9990f860eb9380837ef431ca02def32c4261ad) by [@j-piasecki](https://github.com/j-piasecki))
#### iOS specific
- **Hermes V1:** Added opt-in to use the new Hermes ([e9cdc308b4](https://github.com/facebook/react-native/commit/e9cdc308b4c04753d85757e8877ac00c3c687b95) by [@j-piasecki](https://github.com/j-piasecki))
### Changed
- **Hermes V1:** Changed the source of hermesc binary to be an npm package ([2e0bd13a25](https://github.com/facebook/react-native/commit/2e0bd13a2533fe7ab64125a95b9215b806018c6e) by [@j-piasecki](https://github.com/j-piasecki))
### Deprecated
- **APIs:** Deprecate legacy javascript react native apis ([e7aeea26bd](https://github.com/facebook/react-native/commit/e7aeea26bde6e9cda0a3a0a55fc2a0421fb0c0e5) by [@RSNara](https://github.com/RSNara))
### Fixed
#### Android specific
- **Build From Source:** Fix build from source due to missing folder error on Gradle 9.0 ([9fbce3eff1](https://github.com/facebook/react-native/commit/9fbce3eff18060f16e796badc415ba733ede19af) by [@cortinico](https://github.com/cortinico))
#### iOS specific
- **RCTAlertController:** Simplify RCTAlertController, don't create additional UIWindow ([05c4321b19](https://github.com/facebook/react-native/commit/05c4321b194c3d0e146b6085bcaccc75acd3fd67) by [@okwasniewski](https://github.com/okwasniewski))
- **Prebuild:** Fix Node scripts related to prebuilt tarball extraction for paths containing whitespaces ([9731e8ebc5](https://github.com/facebook/react-native/commit/9731e8ebc5ea87526a91b9903172639e062cd920) by [@kitten](https://github.com/kitten))
- **Prebuild:** Use autolinking-generated react-native-config output in second step of cocoapods linking that generates artifacts and generated source ([f170db412b](https://github.com/facebook/react-native/commit/f170db412b3ab46fd0894d5d66431d9c230cd3a8) by [@kitten](https://github.com/kitten))
## v0.82.0-rc.0
### Breaking
+5 -2
View File
@@ -17,10 +17,13 @@
<img src="https://img.shields.io/npm/v/react-native?color=brightgreen&label=npm%20package" alt="Current npm package version." />
</a>
<a href="https://reactnative.dev/docs/contributing">
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome!" />
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs are welcome!" />
</a>
<a href="https://twitter.com/intent/follow?screen_name=reactnative">
<img src="https://img.shields.io/twitter/follow/reactnative.svg?label=Follow%20@reactnative" alt="Follow @reactnative" />
<img src="https://img.shields.io/twitter/follow/reactnative.svg?label=Follow%20@reactnative" alt="Follow @reactnative on X" />
</a>
<a href="https://bsky.app/profile/reactnative.dev">
<img src="https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff" alt="Follow @reactnative.dev on Bluesky" />
</a>
</p>
+1 -1
View File
@@ -100,7 +100,7 @@
"jsonc-parser": "2.2.1",
"markdownlint-cli2": "^0.17.2",
"markdownlint-rule-relative-links": "^3.0.0",
"memfs": "^4.7.7",
"memfs": "^4.38.2",
"metro-babel-register": "^0.83.1",
"metro-transform-plugins": "^0.83.1",
"micromatch": "^4.0.4",
+2 -2
View File
@@ -1,5 +1,5 @@
@generated SignedSource<<b6a779e724ecce5e727ee674dc20f809>>
Git revision: e87564a24cf233c60aaebee8c418ec85724f7214
@generated SignedSource<<0b54f75686e4893a5444839bf621a317>>
Git revision: 5a792db1225adda206313e9bf751198a1ca7851a
Built with --nohooks: false
Is local checkout: false
Remote URL: https://github.com/facebook/react-native-devtools-frontend
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -238,7 +238,7 @@ import"../../ui/components/icon_button/icon_button.js";import"../../ui/component
<td>${e.method}</td>
<td>${e.params?d`<code>${JSON.stringify(e.params)}</code>`:""}</td>
<td>
${e.result?d`<code>${JSON.stringify(e.result)}</code>`:e.error?d`<code>${JSON.stringify(e.error)}</code>`:"(pending)"}
${e.result?d`<code>${JSON.stringify(e.result)}</code>`:e.error?d`<code>${JSON.stringify(e.error)}</code>`:"id"in e?"(pending)":""}
</td>
<td data-value=${e.elapsedTime||0}>
${"id"in e?e.elapsedTime?U(A.sMs,{PH1:String(e.elapsedTime)}):"(pending)":""}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -23,6 +23,7 @@ import com.facebook.react.utils.PropertyUtils.SCOPED_USE_THIRD_PARTY_JSC
import com.facebook.react.utils.PropertyUtils.USE_THIRD_PARTY_JSC
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.jetbrains.kotlin.gradle.plugin.extraProperties
internal object ProjectUtils {
@@ -75,7 +76,11 @@ internal object ProjectUtils {
(project.hasProperty(HERMES_V1_ENABLED) &&
project.property(HERMES_V1_ENABLED).toString().toBoolean()) ||
(project.hasProperty(SCOPED_HERMES_V1_ENABLED) &&
project.property(SCOPED_HERMES_V1_ENABLED).toString().toBoolean())
project.property(SCOPED_HERMES_V1_ENABLED).toString().toBoolean()) ||
(project.extraProperties.has(HERMES_V1_ENABLED) &&
project.extraProperties.get(HERMES_V1_ENABLED).toString().toBoolean()) ||
(project.extraProperties.has(SCOPED_HERMES_V1_ENABLED) &&
project.extraProperties.get(SCOPED_HERMES_V1_ENABLED).toString().toBoolean())
internal fun Project.needsCodegenFromPackageJson(rootProperty: DirectoryProperty): Boolean {
val parsedPackageJson = readPackageJsonFile(this, rootProperty)
@@ -33,9 +33,9 @@ class GeneratePackageListTaskTest {
val inputFile = tempFolder.newFile("config.json")
val task =
createTestTask<GeneratePackageListTask> {
it.generatedOutputDirectory.set(outputFolder)
it.autolinkInputFile.set(inputFile)
createTestTask<GeneratePackageListTask> { testTask ->
testTask.generatedOutputDirectory.set(outputFolder)
testTask.autolinkInputFile.set(inputFile)
}
assertThat(task.inputs.files.singleFile).isEqualTo(inputFile)
@@ -82,11 +82,11 @@ class PrepareGflagsTaskTest {
val gflagsThirdPartyPath = tempFolder.newFolder("gflagspath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareGflagsTask> {
it.gflagsPath.setFrom(gflagspath)
it.gflagsThirdPartyPath.set(gflagsThirdPartyPath)
it.gflagsVersion.set("1.0.0")
it.outputDir.set(output)
createTestTask<PrepareGflagsTask> { taskConfig ->
taskConfig.gflagsPath.setFrom(gflagspath)
taskConfig.gflagsThirdPartyPath.set(gflagsThirdPartyPath)
taskConfig.gflagsVersion.set("1.0.0")
taskConfig.outputDir.set(output)
}
File(gflagspath, "gflags-1.0.0/src/gflags_declare.h.in").apply {
parentFile.mkdirs()
@@ -25,14 +25,14 @@ class OsRule : TestRule {
override fun evaluate() {
val annotation = description.annotations.filterIsInstance<WithOs>().firstOrNull()
annotation?.os?.propertyName?.let {
annotation?.os?.propertyName?.let { osName ->
retainOs = System.getProperty(OS_NAME_KEY)
System.setProperty(OS_NAME_KEY, it)
System.setProperty(OS_NAME_KEY, osName)
}
annotation?.arch?.let {
if (it.isNotBlank()) {
annotation?.arch?.let { arch ->
if (arch.isNotBlank()) {
retainArch = System.getProperty(OS_ARCH_KEY)
System.setProperty(OS_ARCH_KEY, it)
System.setProperty(OS_ARCH_KEY, arch)
}
}
try {
@@ -5,8 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridgeDelegate.h>
#import <React/RCTConvert.h>
#import <UIKit/UIKit.h>
#import "RCTDefaultReactNativeFactoryDelegate.h"
#import "RCTReactNativeFactory.h"
@@ -6,6 +6,7 @@
*/
#import "RCTAppDelegate.h"
#import <React/RCTBridgeDelegate.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
@@ -6,6 +6,7 @@
*
* @flow strict
* @format
* @deprecated
*/
'use strict';
@@ -6,6 +6,7 @@
*
* @flow strict
* @format
* @deprecated
*/
'use strict';
@@ -6,6 +6,7 @@
*
* @flow
* @format
* @deprecated
*/
import NativeTiming from './NativeTiming';
@@ -6,6 +6,7 @@
*
* @flow strict
* @format
* @deprecated
*/
export * from '../../../src/private/specs_DEPRECATED/modules/NativeTiming';
@@ -6,6 +6,7 @@
*
* @flow
* @format
* @deprecated
*/
'use strict';
@@ -10,9 +10,9 @@
#import "RCTNetworkConversions.h"
#import <React/RCTLog.h>
#import <jsinspector-modern/network/NetworkReporter.h>
#import <react/networking/NetworkReporter.h>
using namespace facebook::react::jsinspector_modern;
using namespace facebook::react;
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
namespace {
@@ -50,6 +50,7 @@ Pod::Spec.new do |s|
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
add_dependency(s, "React-NativeModulesApple", :additional_framework_paths => ["build/generated/ios"])
add_dependency(s, "React-networking", :framework_name => 'React_networking')
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
@@ -7,7 +7,7 @@
* @noformat
* @nolint
* @flow strict
* @generated SignedSource<<deb7924d11c790f99448a1c2f0edddb9>>
* @generated SignedSource<<c0e57723772ea5f1aa8c3c897ac3c216>>
*/
import type {
@@ -135,6 +135,7 @@ export type RenderRootOptions = {
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
onDefaultTransitionIndicator?: () => void | (() => void),
};
/**
@@ -67,7 +67,7 @@ template <typename T>
facebook::react::LazyVector<T> RCTBridgingToVec(id value, T (^ctor)(id element))
{
NSArray *array = RCTBridgingToArray(value);
typedef typename facebook::react::LazyVector<T>::size_type _size_t;
using _size_t = typename facebook::react::LazyVector<T>::size_type;
_size_t size = static_cast<_size_t>(array.count);
return facebook::react::LazyVector<T>::fromUnsafeRawValue(array, size, ctor);
}
+23
View File
@@ -211,6 +211,18 @@ let reactHermes = RNTarget(
]
)
/// React-networking.podspec
let reactNetworking = RNTarget(
name: .reactNetworking,
path: "ReactCommon/react/networking",
excludedPaths: ["tests"],
dependencies: [.reactNativeDependencies, .reactJsInspectorNetwork, .reactPerformanceTimeline],
defines: [
CXXSetting.define("REACT_NATIVE_DEBUGGER_ENABLED", to: "1", .when(configuration: BuildConfiguration.debug)),
CXXSetting.define("REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY", to: "1", .when(configuration: BuildConfiguration.debug)),
]
)
/// React-performancecdpmetrics.podspec
let reactPerformanceCdpMetrics = RNTarget(
name: .reactPerformanceCdpMetrics,
@@ -304,6 +316,13 @@ let reactIdleCallbacksNativeModule = RNTarget(
dependencies: [.reactNativeDependencies, .reactDebug, .reactFeatureFlags, .reactUtils, .reactPerfLogger, .reactCxxReact, .reactTurboModuleCore]
)
/// React-webperformance.podspec
let reactWebPerformanceNativeModule = RNTarget(
name: .reactWebPerformanceNativeModule,
path: "ReactCommon/react/nativemodule/webperformance",
dependencies: [.reactNativeDependencies, .reactCxxReact, .reactTurboModuleCore, .reactPerformanceTimeline]
)
/// React-featureflagnativemodule.podspec
let reactFeatureflagsNativemodule = RNTarget(
name: .reactFeatureflagsNativemodule,
@@ -566,6 +585,7 @@ let targets = [
reactNativeDependencies,
hermesPrebuilt,
reactJsiTooling,
reactNetworking,
reactPerformanceCdpMetrics,
reactPerformanceTimeline,
reactRuntimeScheduler,
@@ -590,6 +610,7 @@ let targets = [
reactTurboModuleCoreDefaults,
reactTurboModuleCoreMicrotasks,
reactIdleCallbacksNativeModule,
reactWebPerformanceNativeModule,
reactFeatureflagsNativemodule,
reactNativeModuleDom,
reactAppDelegate,
@@ -737,6 +758,7 @@ extension String {
static let hermesPrebuilt = "hermes-prebuilt"
static let reactJsiTooling = "React-jsitooling"
static let reactNetworking = "React-networking"
static let reactPerformanceCdpMetrics = "React-performancecdpmetrics"
static let reactPerformanceTimeline = "React-performancetimeline"
static let reactRuntimeScheduler = "React-runtimescheduler"
@@ -764,6 +786,7 @@ extension String {
static let reactTurboModuleCoreDefaults = "ReactCommon/turbomodule/core/defaults"
static let reactTurboModuleCoreMicrotasks = "ReactCommon/turbomodule/core/microtasks"
static let reactIdleCallbacksNativeModule = "React-idlecallbacksnativemodule"
static let reactWebPerformanceNativeModule = "React-webperformancenativemodule"
static let reactFeatureflagsNativemodule = "React-featureflagsnativemodule"
static let reactNativeModuleDom = "React-domnativemodule"
static let reactAppDelegate = "React-RCTAppDelegate"
+3 -3
View File
@@ -721,13 +721,13 @@ NSData *__nullable RCTGzipData(NSData *__nullable input, float level)
void *libz = dlopen("/usr/lib/libz.dylib", RTLD_LAZY);
typedef int (*DeflateInit2_)(z_streamp, int, int, int, int, int, const char *, int);
using DeflateInit2_ = int (*)(z_streamp, int, int, int, int, int, const char *, int);
DeflateInit2_ deflateInit2_ = (DeflateInit2_)dlsym(libz, "deflateInit2_");
typedef int (*Deflate)(z_streamp, int);
using Deflate = int (*)(z_streamp, int);
Deflate deflate = (Deflate)dlsym(libz, "deflate");
typedef int (*DeflateEnd)(z_streamp);
using DeflateEnd = int (*)(z_streamp);
DeflateEnd deflateEnd = (DeflateEnd)dlsym(libz, "deflateEnd");
z_stream stream;
@@ -238,11 +238,10 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
- (void)interfaceOrientationDidChange
{
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
UIApplication *application = RCTSharedApplication();
UIInterfaceOrientation nextOrientation = RCTKeyWindow().windowScene.interfaceOrientation;
UIWindow *window = RCTKeyWindow();
UIInterfaceOrientation nextOrientation = window.windowScene.interfaceOrientation;
BOOL isRunningInFullScreen =
CGRectEqualToRect(application.delegate.window.frame, application.delegate.window.screen.bounds);
BOOL isRunningInFullScreen = window ? CGRectEqualToRect(window.frame, window.screen.bounds) : YES;
// We are catching here two situations for multitasking view:
// a) The app is in Split View and the container gets resized -> !isRunningInFullScreen
// b) The app changes to/from fullscreen example: App runs in slide over mode and goes into fullscreen->
@@ -91,9 +91,9 @@ Pod::Spec.new do |s|
add_dependency(s, "React-RCTAnimation", :framework_name => 'RCTAnimation')
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
add_dependency(s, "React-performancecdpmetrics", :framework_name => 'React_performancecdpmetrics')
add_dependency(s, "React-networking", :framework_name => 'React_networking')
add_dependency(s, "React-renderercss")
add_dependency(s, "React-RCTFBReactNativeSpec")
@@ -88,7 +88,7 @@ val hermesVersionProvider: Provider<String> =
val hermesVersionFile =
File(
reactNativeRootDir,
if (hermesV1Enabled) "sdks/.hermesv1version" else "\"sdks/.hermesversion\"",
if (hermesV1Enabled) "sdks/.hermesv1version" else "sdks/.hermesversion",
)
if (hermesVersionFile.exists()) {
@@ -96,7 +96,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
private final TraceListener mTraceListener;
private final JavaScriptModuleRegistry mJSModuleRegistry;
private final JSBundleLoader mJSBundleLoader;
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<>();
private final Object mJSCallsPendingInitLock = new Object();
private final NativeModuleRegistry mNativeModuleRegistry;
@@ -83,6 +83,6 @@ internal class BridgelessDevSupportManager(
}
fun tracingState(): TracingState {
return TracingState.DISABLED
return TracingState.ENABLEDINCDPMODE
}
}
@@ -68,6 +68,7 @@ import com.facebook.react.devsupport.interfaces.StackFrame
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.interfaces.TracingStateProvider
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
import com.facebook.react.devsupport.perfmonitor.PerfMonitorOverlayManager
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
import com.facebook.react.modules.core.RCTNativeAppEventEmitter
@@ -77,6 +78,7 @@ import java.io.File
import java.net.MalformedURLException
import java.net.URL
import java.util.Locale
import javax.inject.Provider
public abstract class DevSupportManagerBase(
protected val applicationContext: Context,
@@ -182,7 +184,7 @@ public abstract class DevSupportManagerBase(
null
}
private var perfMonitorOverlayManager: PerfMonitorOverlayViewManager? = null
private var perfMonitorOverlayManager: PerfMonitorOverlayManager? = null
private var tracingStateProvider: TracingStateProvider? = null
init {
@@ -215,19 +217,19 @@ public abstract class DevSupportManagerBase(
if (
ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
ReactNativeFeatureFlags.perfMonitorV2Enabled() &&
reactInstanceDevHelper is PerfMonitorDevHelper &&
perfMonitorOverlayManager == null
reactInstanceDevHelper is PerfMonitorDevHelper
) {
perfMonitorOverlayManager =
PerfMonitorOverlayViewManager(
Supplier {
PerfMonitorOverlayManager(
reactInstanceDevHelper,
Provider {
val context = reactInstanceDevHelper.currentActivity
if (context == null || context.isFinishing) {
return@Supplier null
return@Provider null
}
context
},
reactInstanceDevHelper.inspectorTarget,
{ openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString()) },
)
}
}
@@ -548,10 +550,11 @@ public abstract class DevSupportManagerBase(
override fun onNewReactContextCreated(reactContext: ReactContext) {
resetCurrentContext(reactContext)
if (perfMonitorOverlayManager != null && reactInstanceDevHelper is PerfMonitorDevHelper) {
if (reactInstanceDevHelper is PerfMonitorDevHelper) {
perfMonitorOverlayManager?.let { manager ->
reactInstanceDevHelper.inspectorTarget?.addPerfMonitorListener(manager)
}
perfMonitorOverlayManager?.enable()
}
}
@@ -882,6 +885,7 @@ public abstract class DevSupportManagerBase(
override fun onPackagerDisconnected() {
isPackagerConnected = false
perfMonitorOverlayManager?.disable()
}
override fun onPackagerReloadCommand() {
@@ -1,20 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.devsupport.interfaces
/** [Experimental] Interface to manage the V2 Perf Monitor overlay. */
internal interface PerfMonitorOverlayManager {
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
public fun enable()
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
public fun disable()
/** Reset the Perf Monitor overlay, e.g. after a reload. */
public fun reset()
}
@@ -7,11 +7,16 @@
package com.facebook.react.devsupport.perfmonitor
import com.facebook.react.devsupport.interfaces.TracingState
/**
* [Experimental] Interface implemented by [com.facebook.react.runtime.ReactHostInspectorTarget]
* exposing actions for the V2 Perf Monitor.
*/
internal interface PerfMonitorInspectorTargetBinding {
/** Get the current CDP or background performance tracing state. */
public fun getTracingState(): TracingState
/** Attempt to pause the current background performance trace, and open in DevTools. */
public fun pauseAndAnalyzeBackgroundTrace()
@@ -0,0 +1,86 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.devsupport.perfmonitor
import android.content.Context
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.devsupport.interfaces.TracingState
import javax.inject.Provider
internal class PerfMonitorOverlayManager(
private val devHelper: PerfMonitorDevHelper,
private val contextProvider: Provider<Context?>,
private val onRequestOpenDevTools: () -> Unit,
) : PerfMonitorUpdateListener {
private var enabled: Boolean = false
private var initialized: Boolean = false
private var view: PerfMonitorOverlayView? = null
private var tracingState: TracingState = TracingState.ENABLEDINCDPMODE
private fun init() {
if (initialized || !enabled) {
return
}
UiThreadUtil.runOnUiThread {
val context = contextProvider.get() ?: return@runOnUiThread
view = PerfMonitorOverlayView(context, ::handleRecordingButtonPress)
// Start background tracing
devHelper.inspectorTarget?.resumeBackgroundTrace()
view?.show()
initialized = true
}
}
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
fun enable() {
enabled = true
init()
UiThreadUtil.runOnUiThread { view?.show() }
}
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
fun disable() {
UiThreadUtil.runOnUiThread { view?.hide() }
enabled = false
}
/** Reset the Perf Monitor overlay, e.g. after a reload. */
fun reset() {
UiThreadUtil.runOnUiThread { view?.resetState() }
// Update with current recording state
onRecordingStateChanged(
devHelper.inspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
)
}
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
view?.updateFocusedEvent(data)
}
override fun onRecordingStateChanged(state: TracingState) {
tracingState = state
view?.updateRecordingState(state)
}
private fun handleRecordingButtonPress() {
when (tracingState) {
TracingState.ENABLEDINBACKGROUNDMODE -> {
devHelper.inspectorTarget?.pauseAndAnalyzeBackgroundTrace()
onRequestOpenDevTools()
}
TracingState.DISABLED -> {
devHelper.inspectorTarget?.resumeBackgroundTrace()
}
TracingState.ENABLEDINCDPMODE -> Unit
}
}
}
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.devsupport
package com.facebook.react.devsupport.perfmonitor
import android.app.Dialog
import android.content.Context
@@ -20,107 +20,110 @@ import android.view.Window
import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.util.Supplier
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.R
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.devsupport.interfaces.PerfMonitorOverlayManager
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTargetBinding
import com.facebook.react.devsupport.perfmonitor.PerfMonitorUpdateListener
import com.facebook.react.uimanager.DisplayMetricsHolder
import com.facebook.react.uimanager.PixelUtil
import java.util.Locale
internal class PerfMonitorOverlayViewManager(
private val contextSupplier: Supplier<Context?>,
private val inspectorTarget: PerfMonitorInspectorTargetBinding?,
) : PerfMonitorOverlayManager, PerfMonitorUpdateListener {
private var initialized: Boolean = false
private var enabled: Boolean = false
private var hasInteractionData: Boolean = false
private var interactionDialog: Dialog? = null
private var buttonDialog: Dialog? = null
private var durationLabel: TextView? = null
internal class PerfMonitorOverlayView(
private val context: Context,
private val onButtonPress: () -> Unit,
) {
private var hidden: Boolean = true
private var hasEventData: Boolean = false
private val metricsDialog: Dialog
private val toolbarDialog: Dialog
private val tooltipDialog: Dialog
private lateinit var buttonLabel: TextView
private lateinit var recordingStateLabel: TextView
private lateinit var durationLabel: TextView
private lateinit var tooltipLabel: TextView
private var ttl: Int = 0
private var hideAfterTimeoutHandler: Handler? = null
override fun enable() {
UiThreadUtil.runOnUiThread {
enabled = true
if (hasInteractionData) {
showOverlay()
}
}
}
override fun disable() {
UiThreadUtil.runOnUiThread {
enabled = false
hideOverlay()
}
}
override fun reset() {
UiThreadUtil.runOnUiThread {
hasInteractionData = false
hideOverlay()
}
}
override fun onRecordingStateChanged(state: TracingState) {
// recordingState = state
// view?.updateRecordingState(state)
}
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
UiThreadUtil.runOnUiThread {
ensureInitialized()
durationLabel?.text = String.format(Locale.US, "%d ms", data.durationMs)
durationLabel?.setTextColor(getDurationHighlightColor(data.responsivenessScore))
hasInteractionData = true
ttl = data.ttl
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
if (enabled) {
showOverlay()
// Schedule hiding overlay after ttl milliseconds
if (ttl > 0) {
if (hideAfterTimeoutHandler == null) {
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
}
hideAfterTimeoutHandler?.postDelayed({ hideOverlay() }, ttl.toLong())
}
}
}
}
private fun ensureInitialized() {
if (initialized) {
return
}
val context = contextSupplier.get() ?: return
init {
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
createDialog(context)
createButton(context)
initialized = true
tooltipDialog = createTooltipDialog()
metricsDialog = createMetricsDialog()
toolbarDialog = createToolbarDialog()
}
private fun showOverlay() {
interactionDialog?.show()
buttonDialog?.show()
fun show() {
toolbarDialog.show()
tooltipDialog.show()
if (hasEventData) {
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
metricsDialog.show()
}
hidden = false
}
private fun hideOverlay() {
interactionDialog?.hide()
buttonDialog?.hide()
fun hide() {
metricsDialog.hide()
toolbarDialog.hide()
tooltipDialog.hide()
hidden = true
}
private fun createDialog(context: Context) {
val containerLayout = createInnerLayout(context)
fun resetState() {
hasEventData = false
metricsDialog.hide()
}
fun updateFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
durationLabel.text = String.format(Locale.US, "%d ms", data.durationMs)
durationLabel.setTextColor(getDurationHighlightColor(data.responsivenessScore))
hasEventData = true
ttl = data.ttl
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
if (!hidden) {
metricsDialog.show()
// Schedule hiding metrics overlay after ttl milliseconds
if (ttl > 0) {
if (hideAfterTimeoutHandler == null) {
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
}
hideAfterTimeoutHandler?.postDelayed({ metricsDialog.hide() }, ttl.toLong())
}
}
}
fun updateRecordingState(state: TracingState) {
recordingStateLabel.text =
when (state) {
TracingState.ENABLEDINBACKGROUNDMODE -> "Profiling: ON"
TracingState.DISABLED -> "Profiling: OFF"
TracingState.ENABLEDINCDPMODE -> "Profiling: DISABLED"
}
buttonLabel.text =
when (state) {
TracingState.ENABLEDINBACKGROUNDMODE -> "Open ↗️"
TracingState.DISABLED -> "Start"
TracingState.ENABLEDINCDPMODE -> ""
}
tooltipLabel.text =
when (state) {
TracingState.ENABLEDINBACKGROUNDMODE -> "Dev Menu > Finish performance trace"
TracingState.DISABLED -> "Dev Menu > Start performance trace"
TracingState.ENABLEDINCDPMODE -> ""
}
if (state == TracingState.ENABLEDINCDPMODE) {
tooltipDialog.hide()
} else {
tooltipDialog.show()
}
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
}
private fun createMetricsDialog(): Dialog {
val containerLayout = createInnerLayout()
val longTaskLabel =
TextView(context).apply {
textSize = TEXT_SIZE_PRIMARY
@@ -138,7 +141,7 @@ internal class PerfMonitorOverlayViewManager(
containerLayout.addView(durationLabel)
val dialog =
createAnchoredDialog(context, dpToPx(140f), dpToPx(16f)).apply {
createAnchoredDialog(getMetricsDialogOffsetX(), dpToPx(16f)).apply {
setContentView(containerLayout)
}
dialog.window?.apply {
@@ -151,30 +154,25 @@ internal class PerfMonitorOverlayViewManager(
}
}
this.interactionDialog = dialog
return dialog
}
fun updateRecordingState(state: TracingState) {}
private fun createButton(context: Context) {
val buttonInner = createInnerLayout(context)
buttonInner.addView(
private fun createToolbarDialog(): Dialog {
val buttonInner = createInnerLayout()
recordingStateLabel =
TextView(context).apply {
text = "Analyze"
textSize = TEXT_SIZE_PRIMARY
setTextColor(Color.WHITE)
typeface = TYPEFACE_BOLD
}
)
buttonInner.addView(
buttonInner.addView(recordingStateLabel)
buttonLabel =
TextView(context).apply {
text = "cmd + A"
textSize = TEXT_SIZE_ACCESSORY
setTextColor(Color.WHITE)
alpha = 0.7f
textSize = TEXT_SIZE_PRIMARY
setTextColor(COLOR_TEXT_BLUE)
typeface = TYPEFACE_BOLD
}
)
buttonInner.addView(buttonLabel)
val buttonView =
LinearLayout(context).apply {
orientation = LinearLayout.VERTICAL
@@ -185,19 +183,43 @@ internal class PerfMonitorOverlayViewManager(
dpToPx(8f).toInt(),
)
addView(buttonInner)
setOnClickListener { inspectorTarget?.pauseAndAnalyzeBackgroundTrace() }
setOnClickListener { onButtonPress() }
}
val dialog =
createAnchoredDialog(context, dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
val dialog = createAnchoredDialog(dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
dialog.window?.apply {
attributes =
attributes?.apply { flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE }
}
this.buttonDialog = dialog
return dialog
}
private fun createAnchoredDialog(context: Context, offsetX: Float, offsetY: Float): Dialog {
private fun createTooltipDialog(): Dialog {
val containerLayout = createInnerLayout()
tooltipLabel =
TextView(context).apply {
textSize = TEXT_SIZE_ACCESSORY
setTextColor(Color.WHITE)
}
containerLayout.addView(tooltipLabel)
val dialog =
createAnchoredDialog(dpToPx(16f), dpToPx(52f)).apply { setContentView(containerLayout) }
dialog.window?.apply {
attributes =
attributes?.apply {
flags =
flags or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
}
}
return dialog
}
private fun createAnchoredDialog(offsetX: Float, offsetY: Float): Dialog {
val dialog =
Dialog(context, R.style.NoAnimationDialog).apply {
requestWindowFeature(Window.FEATURE_NO_TITLE)
@@ -228,12 +250,12 @@ internal class PerfMonitorOverlayViewManager(
return dialog
}
private fun createInnerLayout(context: Context): LinearLayout {
private fun createInnerLayout(): LinearLayout {
return LinearLayout(context).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER_VERTICAL
val paddingHorizontal = dpToPx(14f).toInt()
val paddingVertical = dpToPx(8f).toInt()
val paddingVertical = dpToPx(7f).toInt()
setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical)
layoutParams =
LinearLayout.LayoutParams(
@@ -256,10 +278,21 @@ internal class PerfMonitorOverlayViewManager(
}
}
private fun getMetricsDialogOffsetX(): Float {
val toolbarWidth = toolbarDialog?.window?.decorView?.width ?: 0
return toolbarWidth.toFloat()
}
private fun updateMetricsDialogPosition() {
metricsDialog?.window?.apply {
attributes = attributes?.apply { x = getMetricsDialogOffsetX().toInt() }
}
}
private fun getDurationHighlightColor(responsivenessScore: Int): Int {
return when (responsivenessScore) {
3 -> COLOR_TEXT_RED
2 -> COLOR_TEXT_YELLOW
2 -> COLOR_TEXT_RED
1 -> COLOR_TEXT_YELLOW
else -> COLOR_TEXT_GREEN
}
}
@@ -270,6 +303,7 @@ internal class PerfMonitorOverlayViewManager(
private val COLOR_TEXT_GREEN = Color.parseColor("#4AEB2F")
private val COLOR_TEXT_YELLOW = Color.parseColor("#FFAA00")
private val COLOR_TEXT_RED = Color.parseColor("#FF0000")
private val COLOR_TEXT_BLUE = Color.parseColor("#00B0FF")
private val COLOR_OVERLAY_BORDER = Color.parseColor("#6C6C6C")
private val TEXT_SIZE_PRIMARY = 13f
private val TEXT_SIZE_ACCESSORY = 9f
@@ -1341,6 +1341,7 @@ public class SurfaceMountingManager {
final boolean mIsRoot;
@Nullable ViewManager mViewManager = null;
@Nullable ReactStylesDiffMap mCurrentProps = null;
@Nullable ReadableMap mCurrentLocalData = null;
@Nullable StateWrapper mStateWrapper = null;
@Nullable EventEmitterWrapper mEventEmitter = null;
@@ -1370,6 +1371,8 @@ public class SurfaceMountingManager {
+ mIsRoot
+ " - props: "
+ mCurrentProps
+ " - localData: "
+ mCurrentLocalData
+ " - viewManager: "
+ mViewManager
+ " - isLayoutOnly: "
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<c217318f9f313103ca31d8e7698851d8>>
* @generated SignedSource<<8300eb10fb4906468cd5f04afd8e16cd>>
*/
/**
@@ -300,6 +300,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableVirtualViewWindowFocusDetection(): Boolean = accessor.enableVirtualViewWindowFocusDetection()
/**
* Enable Web Performance APIs (Performance Timeline, User Timings, etc.) by default.
*/
@JvmStatic
public fun enableWebPerformanceAPIsByDefault(): Boolean = accessor.enableWebPerformanceAPIsByDefault()
/**
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<4ed350d8dfa42caf27d346dfcfbed974>>
* @generated SignedSource<<ea5133af611c4d1e7e70155a3a74492d>>
*/
/**
@@ -65,6 +65,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
private var enableVirtualViewRenderStateCache: Boolean? = null
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
@@ -496,6 +497,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun enableWebPerformanceAPIsByDefault(): Boolean {
var cached = enableWebPerformanceAPIsByDefaultCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableWebPerformanceAPIsByDefault()
enableWebPerformanceAPIsByDefaultCache = cached
}
return cached
}
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<6c201de02071a834e411b6761d7f863b>>
* @generated SignedSource<<cf5b9f099846d4f954304905f77ebe17>>
*/
/**
@@ -118,6 +118,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun enableVirtualViewWindowFocusDetection(): Boolean
@DoNotStrip @JvmStatic public external fun enableWebPerformanceAPIsByDefault(): Boolean
@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7c4c3bf6b720f3e15fb97d8f1a4d74ba>>
* @generated SignedSource<<305496047314dc97352a6e0dad0bba54>>
*/
/**
@@ -113,6 +113,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun enableVirtualViewWindowFocusDetection(): Boolean = false
override fun enableWebPerformanceAPIsByDefault(): Boolean = false
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
override fun fuseboxEnabledRelease(): Boolean = false
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<57fca2370d6b3f1edf7045a0b4c94350>>
* @generated SignedSource<<f3798eada96337cf98715fa580823b30>>
*/
/**
@@ -69,6 +69,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
private var enableVirtualViewRenderStateCache: Boolean? = null
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
@@ -545,6 +546,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun enableWebPerformanceAPIsByDefault(): Boolean {
var cached = enableWebPerformanceAPIsByDefaultCache
if (cached == null) {
cached = currentProvider.enableWebPerformanceAPIsByDefault()
accessedFeatureFlags.add("enableWebPerformanceAPIsByDefault")
enableWebPerformanceAPIsByDefaultCache = cached
}
return cached
}
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ef31518f0fe8ff6f6a5c15936cab9d87>>
* @generated SignedSource<<c36e7ac588eb68660f000e7792ec2384>>
*/
/**
@@ -113,6 +113,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun enableVirtualViewWindowFocusDetection(): Boolean
@DoNotStrip public fun enableWebPerformanceAPIsByDefault(): Boolean
@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
@DoNotStrip public fun fuseboxEnabledRelease(): Boolean
@@ -310,8 +310,8 @@ public open class JavaTimerManager(
}
}
}
timersToCall?.let {
javaScriptTimerExecutor.callTimers(it)
timersToCall?.let { timers ->
javaScriptTimerExecutor.callTimers(timers)
timersToCall = null
}
reactChoreographer.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this)
@@ -81,6 +81,6 @@ internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
delegate.loadBundle(bundleLoader)
override fun getTracingState(): TracingState {
return delegate.reactHostInspectorTarget?.tracingState() ?: TracingState.DISABLED
return delegate.reactHostInspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
}
}
@@ -43,7 +43,7 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :
external fun tracingStateAsInt(): Int
fun tracingState(): TracingState {
override fun getTracingState(): TracingState {
return TracingState.entries[tracingStateAsInt()]
}
@@ -124,6 +124,8 @@ add_react_common_subdir(react/nativemodule/dom)
add_react_common_subdir(react/nativemodule/featureflags)
add_react_common_subdir(react/nativemodule/microtasks)
add_react_common_subdir(react/nativemodule/idlecallbacks)
add_react_common_subdir(react/nativemodule/webperformance)
add_react_common_subdir(react/networking)
add_react_common_subdir(jserrorhandler)
add_react_common_subdir(react/runtime)
add_react_common_subdir(react/runtime/hermes)
@@ -190,6 +192,8 @@ add_library(reactnative
$<TARGET_OBJECTS:react_nativemodule_featureflags>
$<TARGET_OBJECTS:react_nativemodule_idlecallbacks>
$<TARGET_OBJECTS:react_nativemodule_microtasks>
$<TARGET_OBJECTS:react_nativemodule_webperformance>
$<TARGET_OBJECTS:react_networking>
$<TARGET_OBJECTS:react_newarchdefaults>
$<TARGET_OBJECTS:react_performance_cdpmetrics>
$<TARGET_OBJECTS:react_performance_timeline>
@@ -279,6 +283,8 @@ target_include_directories(reactnative
$<TARGET_PROPERTY:react_nativemodule_featureflags,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_nativemodule_idlecallbacks,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_nativemodule_microtasks,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_nativemodule_webperformance,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_networking,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_newarchdefaults,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_performance_cdpmetrics,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_performance_timeline,INTERFACE_INCLUDE_DIRECTORIES>
@@ -20,6 +20,6 @@ target_include_directories(react_devsupportjni PUBLIC .)
target_link_libraries(react_devsupportjni
fbjni
jsinspector
jsinspector_network)
react_networking)
target_compile_reactnative_options(react_devsupportjni PRIVATE)
@@ -7,7 +7,7 @@
#include "JInspectorNetworkReporter.h"
#include <jsinspector-modern/network/NetworkReporter.h>
#include <react/networking/NetworkReporter.h>
#include <cstddef>
#include <string>
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<846db2d7c3c6020dec04789fe2784f8a>>
* @generated SignedSource<<be39ff0cb3b7c5881510b1528c17465a>>
*/
/**
@@ -309,6 +309,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}
bool enableWebPerformanceAPIsByDefault() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableWebPerformanceAPIsByDefault");
return method(javaProvider_);
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixMappingOfEventPrioritiesBetweenFabricAndReact");
@@ -688,6 +694,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection(
return ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection();
}
bool JReactNativeFeatureFlagsCxxInterop::enableWebPerformanceAPIsByDefault(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault();
}
bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
@@ -979,6 +990,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"enableVirtualViewWindowFocusDetection",
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection),
makeNativeMethod(
"enableWebPerformanceAPIsByDefault",
JReactNativeFeatureFlagsCxxInterop::enableWebPerformanceAPIsByDefault),
makeNativeMethod(
"fixMappingOfEventPrioritiesBetweenFabricAndReact",
JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e4d45c3e12ab378a5b99d14f7f0ed4fd>>
* @generated SignedSource<<8cd0afd7badb6739b4e8f9b0e630677c>>
*/
/**
@@ -165,6 +165,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool enableVirtualViewWindowFocusDetection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool enableWebPerformanceAPIsByDefault(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -28,7 +28,7 @@ target_compile_reactnative_options(hermes_executor PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(hermes_executor PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(hermes_executor PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif()
@@ -30,7 +30,7 @@ target_compile_reactnative_options(hermesinstancejni PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(hermesinstancejni PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(hermesinstancejni PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif ()
@@ -20,7 +20,7 @@ target_compile_reactnative_options(rninstance PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(rninstance PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(rninstance PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif ()
@@ -33,7 +33,7 @@ if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
-DHERMES_ENABLE_DEBUGGER=1
)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(hermes_executor_common PRIVATE -DHERMES_V1_ENABLED=1)
endif()
else()
@@ -24,7 +24,7 @@ if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
-DHERMES_ENABLE_DEBUGGER=1
)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(hermes_inspector_modern PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif()
@@ -11,7 +11,7 @@
#include "Base64.h"
#include "Utf8.h"
#include <jsinspector-modern/network/NetworkReporter.h>
#include <jsinspector-modern/network/NetworkHandler.h>
#include <sstream>
#include <tuple>
@@ -272,19 +272,19 @@ bool NetworkIOAgent::handleRequest(
}
if (InspectorFlags::getInstance().getNetworkInspectionEnabled()) {
auto& networkReporter = NetworkReporter::getInstance();
auto& networkHandler = NetworkHandler::getInstance();
// @cdp Network.enable support is experimental.
if (req.method == "Network.enable") {
networkReporter.setFrontendChannel(frontendChannel_);
networkReporter.enableDebugging();
networkHandler.setFrontendChannel(frontendChannel_);
networkHandler.enable();
frontendChannel_(cdp::jsonResult(req.id));
return true;
}
// @cdp Network.disable support is experimental.
if (req.method == "Network.disable") {
networkReporter.disableDebugging();
networkHandler.disable();
frontendChannel_(cdp::jsonResult(req.id));
return true;
}
@@ -497,9 +497,9 @@ void NetworkIOAgent::handleGetResponseBody(const cdp::PreparsedRequest& req) {
return;
}
auto& networkReporter = NetworkReporter::getInstance();
auto& networkHandler = NetworkHandler::getInstance();
if (!networkReporter.isDebuggingEnabled()) {
if (!networkHandler.isEnabled()) {
frontendChannel_(cdp::jsonError(
requestId,
cdp::ErrorCode::InvalidRequest,
@@ -508,7 +508,7 @@ void NetworkIOAgent::handleGetResponseBody(const cdp::PreparsedRequest& req) {
}
auto storedResponse =
networkReporter.getResponseBody(req.params.at("requestId").asString());
networkHandler.getResponseBody(req.params.at("requestId").asString());
if (!storedResponse) {
frontendChannel_(cdp::jsonError(
@@ -50,7 +50,8 @@ void PerfMonitorUpdateHandler::handlePerfMetricsUpdate(
}
auto responsivenessScore = getInteractionScore(duration);
auto ttl = responsivenessScore == InteractionResponsivenessScore::Poor
auto ttl =
responsivenessScore == InteractionResponsivenessScore::NeedsImprovement
? BAD_EVENT_TTL
: DEFAULT_TTL;
@@ -24,6 +24,4 @@ target_include_directories(jsinspector_network PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(jsinspector_network
folly_runtime
glog
jsinspector_cdp
react_performance_timeline
react_timing)
jsinspector_cdp)
@@ -27,15 +27,6 @@ folly::dynamic headersToDynamic(const std::optional<Headers>& headers) {
} // namespace
/* static */ Request Request::fromInputParams(const RequestInfo& requestInfo) {
return {
.url = requestInfo.url,
.method = requestInfo.httpMethod,
.headers = requestInfo.headers,
.postData = requestInfo.httpBody,
};
}
folly::dynamic Request::toDynamic() const {
folly::dynamic result = folly::dynamic::object;
@@ -48,16 +39,16 @@ folly::dynamic Request::toDynamic() const {
}
/* static */ Response Response::fromInputParams(
const ResponseInfo& responseInfo,
const std::string& url,
uint16_t status,
const std::optional<Headers>& headers,
int encodedDataLength) {
auto headers = responseInfo.headers.value_or(Headers());
return {
.url = responseInfo.url,
.status = responseInfo.statusCode,
.statusText = httpReasonPhrase(responseInfo.statusCode),
.url = url,
.status = status,
.statusText = httpReasonPhrase(status),
.headers = headers,
.mimeType = mimeTypeFromHeaders(headers),
.mimeType = mimeTypeFromHeaders(headers.value_or(Headers())),
.encodedDataLength = encodedDataLength,
};
}
@@ -7,8 +7,6 @@
#pragma once
#include "NetworkTypes.h"
#include <folly/dynamic.h>
#include <string>
@@ -18,6 +16,8 @@
namespace facebook::react::jsinspector_modern::cdp::network {
using Headers = std::map<std::string, std::string>;
/**
* https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Request
*/
@@ -27,12 +27,6 @@ struct Request {
std::optional<Headers> headers;
std::optional<std::string> postData;
/**
* Convenience function to construct a `Request` from the generic
* `RequestInfo` input object.
*/
static Request fromInputParams(const RequestInfo& requestInfo);
folly::dynamic toDynamic() const;
};
@@ -52,7 +46,9 @@ struct Response {
* `ResponseInfo` input object.
*/
static Response fromInputParams(
const ResponseInfo& responseInfo,
const std::string& url,
uint16_t status,
const std::optional<Headers>& headers,
int encodedDataLength);
folly::dynamic toDynamic() const;
@@ -146,7 +146,8 @@ std::string httpReasonPhrase(uint16_t status) {
return "<Unknown>";
}
std::string mimeTypeFromHeaders(const Headers& headers) {
std::string mimeTypeFromHeaders(
const std::map<std::string, std::string>& headers) {
std::string mimeType = "application/octet-stream";
for (const auto& [name, value] : headers) {
@@ -7,8 +7,7 @@
#pragma once
#include "NetworkTypes.h"
#include <map>
#include <string>
namespace facebook::react::jsinspector_modern {
@@ -22,6 +21,7 @@ std::string httpReasonPhrase(uint16_t status);
* Get the MIME type for a response based on the 'Content-Type' header. If
* the header is not present, returns 'application/octet-stream'.
*/
std::string mimeTypeFromHeaders(const Headers& headers);
std::string mimeTypeFromHeaders(
const std::map<std::string, std::string>& headers);
} // namespace facebook::react::jsinspector_modern
@@ -0,0 +1,209 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "NetworkHandler.h"
#include <jsinspector-modern/cdp/CdpJson.h>
#include <glog/logging.h>
#include <chrono>
namespace facebook::react::jsinspector_modern {
namespace {
/**
* Get the current Unix timestamp in seconds (µs precision, CDP format).
*/
double getCurrentUnixTimestampSeconds() {
auto now = std::chrono::system_clock::now().time_since_epoch();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(now).count();
auto micros =
std::chrono::duration_cast<std::chrono::microseconds>(now).count() %
1000000;
return static_cast<double>(seconds) +
(static_cast<double>(micros) / 1000000.0);
}
} // namespace
NetworkHandler& NetworkHandler::getInstance() {
static NetworkHandler instance;
return instance;
}
void NetworkHandler::setFrontendChannel(FrontendChannel frontendChannel) {
frontendChannel_ = std::move(frontendChannel);
}
bool NetworkHandler::enable() {
if (enabled_.load(std::memory_order_acquire)) {
return false;
}
enabled_.store(true, std::memory_order_release);
return true;
}
bool NetworkHandler::disable() {
if (!enabled_.load(std::memory_order_acquire)) {
return false;
}
enabled_.store(false, std::memory_order_release);
requestBodyBuffer_.clear();
return true;
}
void NetworkHandler::onRequestWillBeSent(
const std::string& requestId,
const cdp::network::Request& request,
const std::optional<cdp::network::Response>& redirectResponse) {
if (!isEnabledNoSync()) {
return;
}
double timestamp = getCurrentUnixTimestampSeconds();
auto params = cdp::network::RequestWillBeSentParams{
.requestId = requestId,
.loaderId = "",
.documentURL = "mobile",
.request = request,
// NOTE: Both timestamp and wallTime use the same unit, however wallTime
// is relative to an "arbitrary epoch". In our implementation, use the
// Unix epoch for both.
.timestamp = timestamp,
.wallTime = timestamp,
.initiator = folly::dynamic::object("type", "script"),
.redirectHasExtraInfo = redirectResponse.has_value(),
.redirectResponse = redirectResponse,
};
frontendChannel_(
cdp::jsonNotification("Network.requestWillBeSent", params.toDynamic()));
}
void NetworkHandler::onRequestWillBeSentExtraInfo(
const std::string& requestId,
const Headers& headers) {
if (!isEnabledNoSync()) {
return;
}
auto params = cdp::network::RequestWillBeSentExtraInfoParams{
.requestId = requestId,
.headers = headers,
.connectTiming = {.requestTime = getCurrentUnixTimestampSeconds()},
};
frontendChannel_(cdp::jsonNotification(
"Network.requestWillBeSentExtraInfo", params.toDynamic()));
}
void NetworkHandler::onResponseReceived(
const std::string& requestId,
const cdp::network::Response& response) {
if (!isEnabledNoSync()) {
return;
}
auto resourceType = cdp::network::resourceTypeFromMimeType(response.mimeType);
resourceTypeMap_.emplace(requestId, resourceType);
auto params = cdp::network::ResponseReceivedParams{
.requestId = requestId,
.loaderId = "",
.timestamp = getCurrentUnixTimestampSeconds(),
.type = resourceType,
.response = response,
.hasExtraInfo = false,
};
frontendChannel_(
cdp::jsonNotification("Network.responseReceived", params.toDynamic()));
}
void NetworkHandler::onDataReceived(
const std::string& requestId,
int dataLength,
int encodedDataLength) {
if (!isEnabledNoSync()) {
return;
}
auto params = cdp::network::DataReceivedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.dataLength = dataLength,
.encodedDataLength = encodedDataLength,
};
frontendChannel_(
cdp::jsonNotification("Network.dataReceived", params.toDynamic()));
}
void NetworkHandler::onLoadingFinished(
const std::string& requestId,
int encodedDataLength) {
if (!isEnabledNoSync()) {
return;
}
auto params = cdp::network::LoadingFinishedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.encodedDataLength = encodedDataLength,
};
frontendChannel_(
cdp::jsonNotification("Network.loadingFinished", params.toDynamic()));
}
void NetworkHandler::onLoadingFailed(
const std::string& requestId,
bool cancelled) const {
if (!isEnabledNoSync()) {
return;
}
auto params = cdp::network::LoadingFailedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.type = resourceTypeMap_.find(requestId) != resourceTypeMap_.end()
? resourceTypeMap_.at(requestId)
: "Other",
.errorText = cancelled ? "net::ERR_ABORTED" : "net::ERR_FAILED",
.canceled = cancelled,
};
frontendChannel_(
cdp::jsonNotification("Network.loadingFailed", params.toDynamic()));
}
void NetworkHandler::storeResponseBody(
const std::string& requestId,
std::string_view body,
bool base64Encoded) {
std::lock_guard<std::mutex> lock(requestBodyMutex_);
requestBodyBuffer_.put(requestId, body, base64Encoded);
}
std::optional<std::tuple<std::string, bool>> NetworkHandler::getResponseBody(
const std::string& requestId) {
std::lock_guard<std::mutex> lock(requestBodyMutex_);
auto responseBody = requestBodyBuffer_.get(requestId);
if (responseBody == nullptr) {
return std::nullopt;
}
return std::make_optional<std::tuple<std::string, bool>>(
responseBody->data, responseBody->base64Encoded);
}
} // namespace facebook::react::jsinspector_modern
@@ -0,0 +1,147 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "BoundedRequestBuffer.h"
#include "CdpNetwork.h"
#include <folly/dynamic.h>
#include <atomic>
#include <mutex>
#include <string>
#include <tuple>
namespace facebook::react::jsinspector_modern {
/**
* A callback that can be used to send debugger messages (method responses and
* events) to the frontend. The message must be a JSON-encoded string.
* The callback may be called from any thread.
*/
using FrontendChannel = std::function<void(std::string_view messageJson)>;
using Headers = std::map<std::string, std::string>;
/**
* [Experimental] Handler for reporting network events via CDP.
*/
class NetworkHandler {
public:
static NetworkHandler& getInstance();
/**
* Set the channel used to send CDP events to the frontend. This should be
* supplied before calling `enable`.
*/
void setFrontendChannel(FrontendChannel frontendChannel);
/**
* Enable network debugging. Returns `false` if already enabled.
*
* @cdp Network.enable
*/
bool enable();
/**
* Disable network debugging. Returns `false` if not initially enabled.
*
* @cdp Network.disable
*/
bool disable();
/**
* Returns whether network debugging is currently enabled.
*/
inline bool isEnabled() const {
return enabled_.load(std::memory_order_acquire);
}
/**
* @cdp Network.requestWillBeSent
*/
void onRequestWillBeSent(
const std::string& requestId,
const cdp::network::Request& request,
const std::optional<cdp::network::Response>& redirectResponse);
/**
* @cdp Network.requestWillBeSentExtraInfo
*/
void onRequestWillBeSentExtraInfo(
const std::string& requestId,
const Headers& headers);
/**
* @cdp Network.responseReceived
*/
void onResponseReceived(
const std::string& requestId,
const cdp::network::Response& response);
/**
* @cdp Network.dataReceived
*/
void onDataReceived(
const std::string& requestId,
int dataLength,
int encodedDataLength);
/**
* @cdp Network.loadingFinished
*/
void onLoadingFinished(const std::string& requestId, int encodedDataLength);
/**
* @cdp Network.loadingFailed
*/
void onLoadingFailed(const std::string& requestId, bool cancelled) const;
/**
* Store the fetched response body for a text or image network response.
*
* Reponse bodies are stored in a bounded buffer with a fixed maximum memory
* size, where oldest responses will be evicted if the buffer is exceeded.
*
* Should be called after checking \ref NetworkHandler::isEnabled.
*/
void storeResponseBody(
const std::string& requestId,
std::string_view body,
bool base64Encoded);
/**
* Retrieve a stored response body for a given request ID.
*
* \returns An optional tuple of [responseBody, base64Encoded]. Returns
* nullopt if no entry is found in the buffer.
*/
std::optional<std::tuple<std::string, bool>> getResponseBody(
const std::string& requestId);
private:
NetworkHandler() = default;
NetworkHandler(const NetworkHandler&) = delete;
NetworkHandler& operator=(const NetworkHandler&) = delete;
~NetworkHandler() = default;
std::atomic<bool> enabled_{false};
inline bool isEnabledNoSync() const {
return enabled_.load(std::memory_order_relaxed);
}
FrontendChannel frontendChannel_;
std::map<std::string, std::string> resourceTypeMap_{};
BoundedRequestBuffer requestBodyBuffer_{};
std::mutex requestBodyMutex_;
};
} // namespace facebook::react::jsinspector_modern
@@ -1,316 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "NetworkReporter.h"
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
#include "CdpNetwork.h"
#endif
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
#include <jsinspector-modern/cdp/CdpJson.h>
#endif
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/performance/timeline/PerformanceEntryReporter.h>
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
#include <chrono>
#endif
#include <glog/logging.h>
#include <stdexcept>
namespace facebook::react::jsinspector_modern {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
namespace {
/**
* Get the current Unix timestamp in seconds (µs precision, CDP format).
*/
double getCurrentUnixTimestampSeconds() {
auto now = std::chrono::system_clock::now().time_since_epoch();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(now).count();
auto micros =
std::chrono::duration_cast<std::chrono::microseconds>(now).count() %
1000000;
return static_cast<double>(seconds) +
(static_cast<double>(micros) / 1000000.0);
}
} // namespace
#endif
NetworkReporter& NetworkReporter::getInstance() {
static NetworkReporter instance;
return instance;
}
void NetworkReporter::setFrontendChannel(FrontendChannel frontendChannel) {
frontendChannel_ = std::move(frontendChannel);
}
bool NetworkReporter::enableDebugging() {
if (debuggingEnabled_.load(std::memory_order_acquire)) {
return false;
}
debuggingEnabled_.store(true, std::memory_order_release);
return true;
}
bool NetworkReporter::disableDebugging() {
if (!debuggingEnabled_.load(std::memory_order_acquire)) {
return false;
}
debuggingEnabled_.store(false, std::memory_order_release);
requestBodyBuffer_.clear();
return true;
}
void NetworkReporter::reportRequestStart(
const std::string& requestId,
const RequestInfo& requestInfo,
int encodedDataLength,
const std::optional<ResponseInfo>& redirectResponse) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
perfTimingsBuffer_.emplace(
requestId,
ResourceTimingData{
.url = requestInfo.url,
.fetchStart = now,
.requestStart = now,
});
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
double timestamp = getCurrentUnixTimestampSeconds();
auto request = cdp::network::Request::fromInputParams(requestInfo);
auto params = cdp::network::RequestWillBeSentParams{
.requestId = requestId,
.loaderId = "",
.documentURL = "mobile",
.request = std::move(request),
// NOTE: Both timestamp and wallTime use the same unit, however wallTime
// is relative to an "arbitrary epoch". In our implementation, use the
// Unix epoch for both.
.timestamp = timestamp,
.wallTime = timestamp,
.initiator = folly::dynamic::object("type", "script"),
.redirectHasExtraInfo = redirectResponse.has_value(),
};
if (redirectResponse.has_value()) {
params.redirectResponse = cdp::network::Response::fromInputParams(
redirectResponse.value(), encodedDataLength);
}
frontendChannel_(
cdp::jsonNotification("Network.requestWillBeSent", params.toDynamic()));
#endif
}
void NetworkReporter::reportConnectionTiming(
const std::string& requestId,
const std::optional<Headers>& headers) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
it->second.connectStart = now;
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
auto params = cdp::network::RequestWillBeSentExtraInfoParams{
.requestId = requestId,
.headers = headers.value_or(Headers{}),
.connectTiming = {.requestTime = getCurrentUnixTimestampSeconds()},
};
frontendChannel_(cdp::jsonNotification(
"Network.requestWillBeSentExtraInfo", params.toDynamic()));
#endif
}
void NetworkReporter::reportResponseStart(
const std::string& requestId,
const ResponseInfo& responseInfo,
int encodedDataLength) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
it->second.connectEnd = now;
it->second.responseStart = now;
it->second.responseStatus = responseInfo.statusCode;
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
auto response =
cdp::network::Response::fromInputParams(responseInfo, encodedDataLength);
auto resourceType = cdp::network::resourceTypeFromMimeType(response.mimeType);
resourceTypeMap_.emplace(requestId, resourceType);
auto params = cdp::network::ResponseReceivedParams{
.requestId = requestId,
.loaderId = "",
.timestamp = getCurrentUnixTimestampSeconds(),
.type = resourceType,
.response = response,
.hasExtraInfo = false,
};
frontendChannel_(
cdp::jsonNotification("Network.responseReceived", params.toDynamic()));
#endif
}
void NetworkReporter::reportDataReceived(
const std::string& requestId,
int dataLength,
const std::optional<int>& encodedDataLength) {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
auto params = cdp::network::DataReceivedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.dataLength = dataLength,
.encodedDataLength = encodedDataLength.value_or(dataLength),
};
frontendChannel_(
cdp::jsonNotification("Network.dataReceived", params.toDynamic()));
#endif
}
void NetworkReporter::reportResponseEnd(
const std::string& requestId,
int encodedDataLength) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Report PerformanceResourceTiming event
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
auto& eventData = it->second;
PerformanceEntryReporter::getInstance()->reportResourceTiming(
eventData.url,
eventData.fetchStart,
eventData.requestStart,
eventData.connectStart.value_or(now),
eventData.connectEnd.value_or(now),
eventData.responseStart.value_or(now),
now,
eventData.responseStatus);
perfTimingsBuffer_.erase(requestId);
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
auto params = cdp::network::LoadingFinishedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.encodedDataLength = encodedDataLength,
};
frontendChannel_(
cdp::jsonNotification("Network.loadingFinished", params.toDynamic()));
#endif
}
void NetworkReporter::reportRequestFailed(
const std::string& requestId,
bool cancelled) const {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
if (!isDebuggingEnabledNoSync()) {
return;
}
auto params = cdp::network::LoadingFailedParams{
.requestId = requestId,
.timestamp = getCurrentUnixTimestampSeconds(),
.type = resourceTypeMap_.find(requestId) != resourceTypeMap_.end()
? resourceTypeMap_.at(requestId)
: "Other",
.errorText = cancelled ? "net::ERR_ABORTED" : "net::ERR_FAILED",
.canceled = cancelled,
};
frontendChannel_(
cdp::jsonNotification("Network.loadingFailed", params.toDynamic()));
#endif
}
void NetworkReporter::storeResponseBody(
const std::string& requestId,
std::string_view body,
bool base64Encoded) {
std::lock_guard<std::mutex> lock(requestBodyMutex_);
requestBodyBuffer_.put(requestId, body, base64Encoded);
}
std::optional<std::tuple<std::string, bool>> NetworkReporter::getResponseBody(
const std::string& requestId) {
std::lock_guard<std::mutex> lock(requestBodyMutex_);
auto responseBody = requestBodyBuffer_.get(requestId);
if (responseBody == nullptr) {
return std::nullopt;
}
return std::make_optional<std::tuple<std::string, bool>>(
responseBody->data, responseBody->base64Encoded);
}
} // namespace facebook::react::jsinspector_modern
@@ -44,9 +44,6 @@ Pod::Spec.new do |s|
resolve_use_frameworks(s, header_mappings_dir: "../..", module_name: module_name)
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
add_dependency(s, "React-featureflags")
s.dependency "React-performancetimeline"
s.dependency "React-timing"
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<fd6af2db2dd4735d70d888bc9fd9487d>>
* @generated SignedSource<<a4fb74cf8a68181f509794e387bf666d>>
*/
/**
@@ -206,6 +206,10 @@ bool ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection() {
return getAccessor().enableVirtualViewWindowFocusDetection();
}
bool ReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault() {
return getAccessor().enableWebPerformanceAPIsByDefault();
}
bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact();
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8979be03db13b9f45d313018192c0c35>>
* @generated SignedSource<<a4a98649c527be3c936c859ddc59cb33>>
*/
/**
@@ -264,6 +264,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool enableVirtualViewWindowFocusDetection();
/**
* Enable Web Performance APIs (Performance Timeline, User Timings, etc.) by default.
*/
RN_EXPORT static bool enableWebPerformanceAPIsByDefault();
/**
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<b0477d29ce6ef9b30118341e2980a93a>>
* @generated SignedSource<<91188495ce43a1e1c820cdc3d6302bda>>
*/
/**
@@ -839,6 +839,24 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewWindowFocusDetection() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::enableWebPerformanceAPIsByDefault() {
auto flagValue = enableWebPerformanceAPIsByDefault_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(45, "enableWebPerformanceAPIsByDefault");
flagValue = currentProvider_->enableWebPerformanceAPIsByDefault();
enableWebPerformanceAPIsByDefault_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
auto flagValue = fixMappingOfEventPrioritiesBetweenFabricAndReact_.load();
@@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(45, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
markFlagAsAccessed(46, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
@@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(46, "fuseboxEnabledRelease");
markFlagAsAccessed(47, "fuseboxEnabledRelease");
flagValue = currentProvider_->fuseboxEnabledRelease();
fuseboxEnabledRelease_ = flagValue;
@@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(47, "fuseboxNetworkInspectionEnabled");
markFlagAsAccessed(48, "fuseboxNetworkInspectionEnabled");
flagValue = currentProvider_->fuseboxNetworkInspectionEnabled();
fuseboxNetworkInspectionEnabled_ = flagValue;
@@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(48, "hideOffscreenVirtualViewsOnIOS");
markFlagAsAccessed(49, "hideOffscreenVirtualViewsOnIOS");
flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS();
hideOffscreenVirtualViewsOnIOS_ = flagValue;
@@ -920,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(49, "overrideBySynchronousMountPropsAtMountingAndroid");
markFlagAsAccessed(50, "overrideBySynchronousMountPropsAtMountingAndroid");
flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid();
overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue;
@@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(50, "perfMonitorV2Enabled");
markFlagAsAccessed(51, "perfMonitorV2Enabled");
flagValue = currentProvider_->perfMonitorV2Enabled();
perfMonitorV2Enabled_ = flagValue;
@@ -956,7 +974,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(51, "preparedTextCacheSize");
markFlagAsAccessed(52, "preparedTextCacheSize");
flagValue = currentProvider_->preparedTextCacheSize();
preparedTextCacheSize_ = flagValue;
@@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(52, "preventShadowTreeCommitExhaustion");
markFlagAsAccessed(53, "preventShadowTreeCommitExhaustion");
flagValue = currentProvider_->preventShadowTreeCommitExhaustion();
preventShadowTreeCommitExhaustion_ = flagValue;
@@ -992,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(53, "shouldPressibilityUseW3CPointerEventsForHover");
markFlagAsAccessed(54, "shouldPressibilityUseW3CPointerEventsForHover");
flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover();
shouldPressibilityUseW3CPointerEventsForHover_ = flagValue;
@@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause()
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(54, "skipActivityIdentityAssertionOnHostPause");
markFlagAsAccessed(55, "skipActivityIdentityAssertionOnHostPause");
flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause();
skipActivityIdentityAssertionOnHostPause_ = flagValue;
@@ -1028,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::sweepActiveTouchOnChildNativeGesturesAndro
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(55, "sweepActiveTouchOnChildNativeGesturesAndroid");
markFlagAsAccessed(56, "sweepActiveTouchOnChildNativeGesturesAndroid");
flagValue = currentProvider_->sweepActiveTouchOnChildNativeGesturesAndroid();
sweepActiveTouchOnChildNativeGesturesAndroid_ = flagValue;
@@ -1046,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(56, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(57, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit(
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(57, "updateRuntimeShadowNodeReferencesOnCommit");
markFlagAsAccessed(58, "updateRuntimeShadowNodeReferencesOnCommit");
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
@@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(58, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(59, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(59, "useFabricInterop");
markFlagAsAccessed(60, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroi
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(60, "useNativeEqualsInNativeReadableArrayAndroid");
markFlagAsAccessed(61, "useNativeEqualsInNativeReadableArrayAndroid");
flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid();
useNativeEqualsInNativeReadableArrayAndroid_ = flagValue;
@@ -1136,7 +1154,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(61, "useNativeTransformHelperAndroid");
markFlagAsAccessed(62, "useNativeTransformHelperAndroid");
flagValue = currentProvider_->useNativeTransformHelperAndroid();
useNativeTransformHelperAndroid_ = flagValue;
@@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(62, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(63, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -1172,7 +1190,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(63, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(64, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -1190,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(64, "useRawPropsJsiValue");
markFlagAsAccessed(65, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -1208,7 +1226,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(65, "useShadowNodeStateOnClone");
markFlagAsAccessed(66, "useShadowNodeStateOnClone");
flagValue = currentProvider_->useShadowNodeStateOnClone();
useShadowNodeStateOnClone_ = flagValue;
@@ -1226,7 +1244,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(66, "useTurboModuleInterop");
markFlagAsAccessed(67, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -1244,7 +1262,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(67, "useTurboModules");
markFlagAsAccessed(68, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -1262,7 +1280,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewHysteresisRatio() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(68, "virtualViewHysteresisRatio");
markFlagAsAccessed(69, "virtualViewHysteresisRatio");
flagValue = currentProvider_->virtualViewHysteresisRatio();
virtualViewHysteresisRatio_ = flagValue;
@@ -1280,7 +1298,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(69, "virtualViewPrerenderRatio");
markFlagAsAccessed(70, "virtualViewPrerenderRatio");
flagValue = currentProvider_->virtualViewPrerenderRatio();
virtualViewPrerenderRatio_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f4faac6988510cde5066898603e2332e>>
* @generated SignedSource<<17f7a8577d05b191010622fb58ba27f8>>
*/
/**
@@ -77,6 +77,7 @@ class ReactNativeFeatureFlagsAccessor {
bool enableVirtualViewDebugFeatures();
bool enableVirtualViewRenderState();
bool enableVirtualViewWindowFocusDetection();
bool enableWebPerformanceAPIsByDefault();
bool fixMappingOfEventPrioritiesBetweenFabricAndReact();
bool fuseboxEnabledRelease();
bool fuseboxNetworkInspectionEnabled();
@@ -113,7 +114,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 70> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 71> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> cdpInteractionMetricsEnabled_;
@@ -160,6 +161,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> enableVirtualViewDebugFeatures_;
std::atomic<std::optional<bool>> enableVirtualViewRenderState_;
std::atomic<std::optional<bool>> enableVirtualViewWindowFocusDetection_;
std::atomic<std::optional<bool>> enableWebPerformanceAPIsByDefault_;
std::atomic<std::optional<bool>> fixMappingOfEventPrioritiesBetweenFabricAndReact_;
std::atomic<std::optional<bool>> fuseboxEnabledRelease_;
std::atomic<std::optional<bool>> fuseboxNetworkInspectionEnabled_;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<68b40caf4c7d5d92cb5d5eb7bde74ab3>>
* @generated SignedSource<<f387394359fc15af1ecad288f08fefe7>>
*/
/**
@@ -207,6 +207,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool enableWebPerformanceAPIsByDefault() override {
return false;
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
return false;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<742e5536d6d174e42a71b205789f93fd>>
* @generated SignedSource<<e70173d99a68270c77447cd13c556f6d>>
*/
/**
@@ -450,6 +450,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::enableVirtualViewWindowFocusDetection();
}
bool enableWebPerformanceAPIsByDefault() override {
auto value = values_["enableWebPerformanceAPIsByDefault"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::enableWebPerformanceAPIsByDefault();
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
auto value = values_["fixMappingOfEventPrioritiesBetweenFabricAndReact"];
if (!value.isNull()) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<40a8180c5d1ebf49c72e6f0fea4201c9>>
* @generated SignedSource<<d8b57edf1ba256965238058533a2ea7d>>
*/
/**
@@ -70,6 +70,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool enableVirtualViewDebugFeatures() = 0;
virtual bool enableVirtualViewRenderState() = 0;
virtual bool enableVirtualViewWindowFocusDetection() = 0;
virtual bool enableWebPerformanceAPIsByDefault() = 0;
virtual bool fixMappingOfEventPrioritiesBetweenFabricAndReact() = 0;
virtual bool fuseboxEnabledRelease() = 0;
virtual bool fuseboxNetworkInspectionEnabled() = 0;
@@ -21,6 +21,7 @@ target_link_libraries(react_nativemodule_defaults
react_nativemodule_featureflags
react_nativemodule_microtasks
react_nativemodule_idlecallbacks
react_nativemodule_webperformance
)
target_compile_reactnative_options(react_nativemodule_defaults PRIVATE)
target_compile_options(react_nativemodule_defaults PRIVATE -Wpedantic)
@@ -6,10 +6,12 @@
*/
#include "DefaultTurboModules.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/nativemodule/dom/NativeDOM.h>
#include <react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h>
#include <react/nativemodule/idlecallbacks/NativeIdleCallbacks.h>
#include <react/nativemodule/microtasks/NativeMicrotasks.h>
#include <react/nativemodule/webperformance/NativePerformance.h>
#ifdef REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY
#include <react/nativemodule/devtoolsruntimesettings/DevToolsRuntimeSettingsModule.h>
@@ -36,6 +38,12 @@ namespace facebook::react {
return std::make_shared<NativeDOM>(jsInvoker);
}
if (ReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault()) {
if (name == NativePerformance::kModuleName) {
return std::make_shared<NativePerformance>(jsInvoker);
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY
if (name == DevToolsRuntimeSettingsModule::kModuleName) {
return std::make_shared<DevToolsRuntimeSettingsModule>(jsInvoker);
@@ -47,8 +47,10 @@ Pod::Spec.new do |s|
add_rncore_dependency(s)
s.dependency "React-domnativemodule"
s.dependency "React-featureflagsnativemodule"
s.dependency "React-microtasksnativemodule"
s.dependency "React-idlecallbacksnativemodule"
s.dependency "React-webperformancenativemodule"
add_dependency(s, "React-RCTFBReactNativeSpec")
add_dependency(s, "React-featureflags")
add_dependency(s, "React-featureflagsnativemodule")
end
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<95f3b1a29280420bf97cdadbcf9f11da>>
* @generated SignedSource<<702c4023cfafdd477cba85c6efe94d93>>
*/
/**
@@ -269,6 +269,11 @@ bool NativeReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection(
return ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection();
}
bool NativeReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault();
}
bool NativeReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<fe8e1bef9e0c34dc88b5edb604ded048>>
* @generated SignedSource<<96e93863588a9878db7c812435564603>>
*/
/**
@@ -126,6 +126,8 @@ class NativeReactNativeFeatureFlags
bool enableVirtualViewWindowFocusDetection(jsi::Runtime& runtime);
bool enableWebPerformanceAPIsByDefault(jsi::Runtime& runtime);
bool fixMappingOfEventPrioritiesBetweenFabricAndReact(jsi::Runtime& runtime);
bool fuseboxEnabledRelease(jsi::Runtime& runtime);
@@ -7,13 +7,13 @@ cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_nativemodule_webperformance_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_nativemodule_webperformance OBJECT ${react_nativemodule_webperformance_SRC})
target_include_directories(react_nativemodule_webperformance PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_nativemodule_webperformance
react_performance_timeline
react_codegen_rncore
react_cxxreact
)
@@ -131,9 +131,18 @@ NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
: NativePerformanceCxxSpec(std::move(jsInvoker)) {}
HighResTimeStamp NativePerformance::now(jsi::Runtime& /*rt*/) {
// This is not spec-compliant, as this is the duration from system boot to
// now, instead of from app startup to now.
// This should be carefully changed eventually.
return HighResTimeStamp::now();
}
HighResDuration NativePerformance::timeOrigin(jsi::Runtime& /*rt*/) {
// This is not spec-compliant, as this is an approximation from Unix epoch to
// system boot, instead of a precise duration from Unix epoch to app startup.
return HighResTimeStamp::unsafeOriginFromUnixTimeStamp();
}
void NativePerformance::reportMark(
jsi::Runtime& rt,
const std::string& name,
@@ -88,6 +88,9 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
// https://www.w3.org/TR/hr-time-3/#now-method
HighResTimeStamp now(jsi::Runtime& rt);
// https://www.w3.org/TR/hr-time-3/#timeorigin-attribute
HighResDuration timeOrigin(jsi::Runtime& rt);
#pragma mark - User Timing Level 3 functions (https://w3c.github.io/user-timing/)
void reportMark(
@@ -0,0 +1,60 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
header_search_paths = []
if ENV['USE_FRAMEWORKS']
header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../../..\"" # this is needed to allow the module access its own files
end
Pod::Spec.new do |s|
s.name = "React-webperformancenativemodule"
s.version = version
s.summary = "React Native idle callbacks native module"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = podspec_sources("*.{cpp,h}", "*.h")
s.header_dir = "react/nativemodule/webperformance"
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"OTHER_CFLAGS" => "$(inherited)",
"DEFINES_MODULE" => "YES" }
if ENV['USE_FRAMEWORKS']
s.module_name = "webperformancenativemodule"
s.header_mappings_dir = "../.."
end
s.dependency "React-jsi"
s.dependency "React-jsiexecutor"
s.dependency "React-cxxreact"
depend_on_js_engine(s)
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
s.dependency "ReactCommon/turbomodule/core"
add_dependency(s, "React-RCTFBReactNativeSpec")
add_dependency(s, "React-performancetimeline")
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
end
@@ -0,0 +1,21 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_networking_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_networking OBJECT ${react_networking_SRC})
target_compile_reactnative_options(react_networking PRIVATE)
target_compile_options(react_networking PRIVATE -Wpedantic)
target_include_directories(react_networking PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_networking
folly_runtime
react_performance_timeline
react_timing)
@@ -0,0 +1,192 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "NetworkReporter.h"
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
#include "jsinspector-modern/network/NetworkHandler.h"
#endif
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/performance/timeline/PerformanceEntryReporter.h>
namespace facebook::react {
NetworkReporter& NetworkReporter::getInstance() {
static NetworkReporter instance;
return instance;
}
bool NetworkReporter::isDebuggingEnabled() const {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
return jsinspector_modern::NetworkHandler::getInstance().isEnabled();
#else
return false;
#endif
}
void NetworkReporter::reportRequestStart(
const std::string& requestId,
const RequestInfo& requestInfo,
int encodedDataLength,
const std::optional<ResponseInfo>& redirectResponse) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
perfTimingsBuffer_.emplace(
requestId,
ResourceTimingData{
.url = requestInfo.url,
.fetchStart = now,
.requestStart = now,
});
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onRequestWillBeSent(
requestId,
{
.url = requestInfo.url,
.method = requestInfo.httpMethod,
.headers = requestInfo.headers,
.postData = requestInfo.httpBody,
},
redirectResponse.has_value()
? std::optional<jsinspector_modern::cdp::network::Response>(
jsinspector_modern::cdp::network::Response::fromInputParams(
redirectResponse->url,
redirectResponse->statusCode,
redirectResponse->headers,
encodedDataLength))
: std::nullopt);
#endif
}
void NetworkReporter::reportConnectionTiming(
const std::string& requestId,
const std::optional<Headers>& headers) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
it->second.connectStart = now;
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance()
.onRequestWillBeSentExtraInfo(requestId, headers.value_or(Headers{}));
#endif
}
void NetworkReporter::reportResponseStart(
const std::string& requestId,
const ResponseInfo& responseInfo,
int encodedDataLength) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
it->second.connectEnd = now;
it->second.responseStart = now;
it->second.responseStatus = responseInfo.statusCode;
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onResponseReceived(
requestId,
jsinspector_modern::cdp::network::Response::fromInputParams(
responseInfo.url,
responseInfo.statusCode,
responseInfo.headers,
encodedDataLength));
#endif
}
void NetworkReporter::reportDataReceived(
const std::string& requestId,
int dataLength,
const std::optional<int>& encodedDataLength) {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onDataReceived(
requestId, dataLength, encodedDataLength.value_or(dataLength));
#endif
}
void NetworkReporter::reportResponseEnd(
const std::string& requestId,
int encodedDataLength) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = HighResTimeStamp::now();
// All builds: Report PerformanceResourceTiming event
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
auto& eventData = it->second;
PerformanceEntryReporter::getInstance()->reportResourceTiming(
eventData.url,
eventData.fetchStart,
eventData.requestStart,
eventData.connectStart.value_or(now),
eventData.connectEnd.value_or(now),
eventData.responseStart.value_or(now),
now,
eventData.responseStatus);
perfTimingsBuffer_.erase(requestId);
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onLoadingFinished(
requestId, encodedDataLength);
#endif
}
void NetworkReporter::reportRequestFailed(
const std::string& requestId,
bool cancelled) const {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onLoadingFailed(
requestId, cancelled);
#endif
}
void NetworkReporter::storeResponseBody(
const std::string& requestId,
std::string_view body,
bool base64Encoded) {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debug build: Store fetched response body for later CDP retrieval
jsinspector_modern::NetworkHandler::getInstance().storeResponseBody(
requestId, body, base64Encoded);
#endif
}
} // namespace facebook::react
@@ -7,27 +7,16 @@
#pragma once
#include "BoundedRequestBuffer.h"
#include "NetworkTypes.h"
#include <folly/dynamic.h>
#include <react/timing/primitives.h>
#include <atomic>
#include <functional>
#include <mutex>
#include <string>
#include <tuple>
#include <unordered_map>
namespace facebook::react::jsinspector_modern {
/**
* A callback that can be used to send debugger messages (method responses and
* events) to the frontend. The message must be a JSON-encoded string.
* The callback may be called from any thread.
*/
using FrontendChannel = std::function<void(std::string_view messageJson)>;
namespace facebook::react {
/**
* Container for static network event metadata aligning with the
@@ -57,34 +46,10 @@ class NetworkReporter {
public:
static NetworkReporter& getInstance();
/**
* Set the channel used to send CDP events to the frontend. This should be
* supplied before calling `enableDebugging`.
*/
void setFrontendChannel(FrontendChannel frontendChannel);
/**
* Enable network tracking over CDP. Once enabled, network events will be
* sent to the debugger client. Returns `false` if already enabled.
*
* Corresponds to `Network.enable` in CDP.
*/
bool enableDebugging();
/**
* Disable network tracking over CDP, preventing network events from being
* sent to the debugger client. Returns `false` if not initially enabled.
*
* Corresponds to `Network.disable` in CDP.
*/
bool disableDebugging();
/**
* Returns whether network tracking over CDP is currently enabled.
*/
inline bool isDebuggingEnabled() const {
return debuggingEnabled_.load(std::memory_order_acquire);
}
bool isDebuggingEnabled() const;
/**
* Report a network request that is about to be sent.
@@ -174,38 +139,14 @@ class NetworkReporter {
std::string_view body,
bool base64Encoded);
/**
* Retrieve a stored response body for a given request ID.
*
* \returns An optional tuple of [responseBody, base64Encoded]. Returns
* nullopt if no entry is found in the buffer.
*/
std::optional<std::tuple<std::string, bool>> getResponseBody(
const std::string& requestId);
private:
NetworkReporter() = default;
NetworkReporter(const NetworkReporter&) = delete;
NetworkReporter& operator=(const NetworkReporter&) = delete;
~NetworkReporter() = default;
std::atomic<bool> debuggingEnabled_{false};
inline bool isDebuggingEnabledNoSync() const {
return debuggingEnabled_.load(std::memory_order_relaxed);
}
FrontendChannel frontendChannel_;
std::unordered_map<std::string, ResourceTimingData> perfTimingsBuffer_{};
std::mutex perfTimingsMutex_;
// Only populated when CDP debugging is enabled.
std::map<std::string, std::string> resourceTypeMap_{};
// Only populated when CDP debugging is enabled.
BoundedRequestBuffer requestBodyBuffer_{};
std::mutex requestBodyMutex_;
};
} // namespace facebook::react::jsinspector_modern
} // namespace facebook::react
@@ -13,7 +13,7 @@
// Defines generic input object types for NetworkReporter.
namespace facebook::react::jsinspector_modern {
namespace facebook::react {
/**
* A collection of parsed HTTP headers.
@@ -39,4 +39,4 @@ struct ResponseInfo {
std::optional<Headers> headers;
};
} // namespace facebook::react::jsinspector_modern
} // namespace facebook::react
@@ -0,0 +1,51 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
header_search_paths = []
if ENV['USE_FRAMEWORKS']
header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../..\"" # this is needed to allow the feature flags access its own files
end
Pod::Spec.new do |s|
s.name = "React-networking"
s.version = version
s.summary = "Common networking modules for React Native"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = podspec_sources("*.{cpp,h}", "*.h")
s.header_dir = "react/networking"
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"DEFINES_MODULE" => "YES" }
if ENV['USE_FRAMEWORKS'] && ReactNativeCoreUtils.build_rncore_from_source()
s.module_name = "React_networking"
s.header_mappings_dir = "../.."
end
add_dependency(s, "React-featureflags")
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
s.dependency "React-performancetimeline"
s.dependency "React-timing"
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
end
@@ -27,10 +27,10 @@ std::optional<double> DynamicEventPayload::extractValue(
auto dynamic = payload_;
for (auto& key : path) {
auto type = dynamic.type();
if ((type == folly::dynamic::Type::OBJECT ||
type == folly::dynamic::Type::ARRAY) &&
!dynamic.empty()) {
if (type == folly::dynamic::Type::OBJECT && !dynamic.empty()) {
dynamic = folly::dynamic(dynamic[key]);
} else if (type == folly::dynamic::Type::ARRAY && !dynamic.empty()) {
dynamic = folly::dynamic(dynamic[std::stoi(key)]);
}
}
if (dynamic.type() == folly::dynamic::Type::DOUBLE) {
@@ -37,6 +37,7 @@ struct TestState {
#endif
};
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
static const char TestComponentName[] = "Test";
class TestProps : public ViewProps {
@@ -19,7 +19,7 @@ target_compile_reactnative_options(bridgeless PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(bridgeless PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(bridgeless PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif ()
@@ -36,7 +36,7 @@ if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
-DHERMES_ENABLE_DEBUGGER=1
)
if (DEFINED HERMES_V1_ENABLED)
if (HERMES_V1_ENABLED)
target_compile_options(bridgelesshermes PRIVATE -DHERMES_V1_ENABLED=1)
endif()
endif()
@@ -201,6 +201,11 @@ class HighResTimeStamp {
return HighResTimeStamp(chronoNow());
}
static HighResDuration unsafeOriginFromUnixTimeStamp() noexcept {
static auto origin = computeUnsafeOriginFromUnixTimeStamp();
return origin;
}
static constexpr HighResTimeStamp min() noexcept {
return HighResTimeStamp(std::chrono::steady_clock::time_point::min());
}
@@ -285,6 +290,13 @@ class HighResTimeStamp {
std::chrono::steady_clock::time_point chronoTimePoint_;
static HighResDuration computeUnsafeOriginFromUnixTimeStamp() noexcept {
auto systemNow = std::chrono::system_clock::now();
auto steadyNow = std::chrono::steady_clock::now();
return HighResDuration(
systemNow.time_since_epoch() - steadyNow.time_since_epoch());
}
#ifdef REACT_NATIVE_DEBUG
static std::function<std::chrono::steady_clock::time_point()>&
getTimeStampProvider() {

Some files were not shown because too many files have changed in this diff Show More