Compare commits

...
Author SHA1 Message Date
Devmate Bot 9b6eb40178 xplat/js/react-native-github/packages/react-native/ReactCommon/jsinspector-modern/Base64.h
Reviewed By: javache

Differential Revision: D82005121
2025-09-10 05:52:58 -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
Nick Lefever 02e3a999ed Back out "Use uint32_t as internal Color representation" (#53622)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53622

Reverting to avoid lossy conversion on hosts expecting signed int values for color conversion.

Changelog: [Internal]

Reviewed By: rozele, javache

Differential Revision: D81785268

fbshipit-source-id: 4a8d099e378fa55e76a58c2ab0356d88e344de2c
2025-09-05 20:37:58 -07:00
Mark Verlingieri 44b2da0df2 Revert D81766029: Make feature flag "enableViewRecyclingForScrollView" true by default
Differential Revision:
D81766029

Original commit changeset: df4a260b9bde

Original Phabricator Diff: D81766029

fbshipit-source-id: f1cd2a2cef632cfe9cbf0cd13e9ec20cfa5cc6ae
2025-09-05 11:58:48 -07:00
Zeya Peng dae2f606c7 Course correct props at SurfaceMountingManager.updateProps() (#53589)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53589

## Changelog:

[Android] [Changed] - [c++ animated] Course correct props at SurfaceMountingManager.updateProps()

Sometimes a React update will try to commit to the same view that native animated modified before via direct manipulation, and after the update host view will use the prop value currently in Fabric. In `AnimatedMountingOverrideDelegate` there's logic to course correct at ShadowTree mount, but if this update is from JS thread, it takes some time to reach mounting layer, at the same time UI thread can still be doing more direct animation updates, and once the corrected change gets there it's already stale.

In this diff I added mechanism to keep track of direct manipulation props (or "synchronous mount props" to match the naming of java function `synchronouslyUpdateView...`) and use it to correct what reaches host view. `SurfaceMountingManager.updateProps()` is called by both regular mount and direct manipulation and it's always called on UI thread, so it could be a good candidate to synchronize these 2 scenarios

Reviewed By: sammy-SC

Differential Revision: D81611823

fbshipit-source-id: 638a59bcd94b3d7e8bab68defd472b2b482dc92f
2025-09-05 09:18:50 -07:00
Zeya Peng 5774bd105d create FeatureFlag overrideBySynchronousMountPropsAtMountingAndroid (#53603)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53603

## Changelog:

[General] [Added] - create FeatureFlag overrideBySynchronousMountPropsAtMountingAndroid

Reviewed By: rshest

Differential Revision: D81690079

fbshipit-source-id: cb381004135ef9cd072c6f99703d9e7f4a40dd6a
2025-09-05 09:18:50 -07:00
generatedunixname89002005287564 3a3f3a417d Fix CQS signal readability-implicit-bool-conversion in xplat/js/react-native-github/packages [B] (#53611)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53611

Reviewed By: rshest

Differential Revision: D81699709

fbshipit-source-id: 6f512fcc01e3f1d33b4e94c4766ee3ab759463e5
2025-09-05 06:37:04 -07:00
Ruslan Shestopalyuk 71edbe1548 Make feature flag "enableViewRecyclingForScrollView" true by default
Summary:
## Changelog:
[Internal] -

Noticed that the default value for this one is inconsistent with all the other similar ones, which can cause confusion during setting up the experiment, fixing it.

Note that top level view recycling is still controlled via `enableViewRecycling`, which will also disable all the other ones when false (which it is by default).

bypass-github-export-checks

Reviewed By: lenaic

Differential Revision: D81766029

fbshipit-source-id: df4a260b9bde20d1c85b7786df00fa91298a27b7
2025-09-05 06:01:47 -07:00
134 changed files with 2348 additions and 896 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:
+5
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
@@ -594,6 +597,7 @@ jobs:
test_js:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
strategy:
fail-fast: false
matrix:
@@ -608,6 +612,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",
@@ -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 {
@@ -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")
@@ -2354,12 +2354,14 @@ public class com/facebook/react/fabric/mounting/SurfaceMountingManager {
public fun sendAccessibilityEvent (II)V
public fun setJSResponder (IIZ)V
public fun stopSurface ()V
public fun storeSynchronousMountPropsOverride (ILcom/facebook/react/bridge/ReadableMap;)V
public fun sweepActiveTouchForTag (I)V
public fun updateEventEmitter (ILcom/facebook/react/fabric/events/EventEmitterWrapper;)V
public fun updateLayout (IIIIIIII)V
public fun updateOverflowInset (IIIII)V
public fun updatePadding (IIIII)V
public fun updateProps (ILcom/facebook/react/bridge/ReadableMap;)V
public fun updatePropsSynchronously (ILcom/facebook/react/bridge/ReadableMap;)V
public fun updateState (ILcom/facebook/react/uimanager/StateWrapper;)V
}
@@ -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()) {
@@ -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
@@ -791,7 +791,8 @@ public class FabricUIManager
@Override
public void execute(MountingManager mountingManager) {
try {
mountingManager.updateProps(reactTag, props);
mountingManager.storeSynchronousMountPropsOverride(reactTag, props);
mountingManager.updatePropsSynchronously(reactTag, props);
} catch (Exception ex) {
// TODO T42943890: Fix animations in Fabric and remove this try/catch?
// There might always be race conditions between surface teardown and
@@ -265,13 +265,23 @@ internal class MountingManager(
}
@UiThread
fun updateProps(reactTag: Int, props: ReadableMap?) {
fun storeSynchronousMountPropsOverride(reactTag: Int, props: ReadableMap?) {
assertOnUiThread()
if (props == null) {
return
}
getSurfaceManagerForViewEnforced(reactTag).updateProps(reactTag, props)
getSurfaceManagerForViewEnforced(reactTag).storeSynchronousMountPropsOverride(reactTag, props)
}
@UiThread
fun updatePropsSynchronously(reactTag: Int, props: ReadableMap?) {
assertOnUiThread()
if (props == null) {
return
}
getSurfaceManagerForViewEnforced(reactTag).updatePropsSynchronously(reactTag, props)
}
/**
@@ -27,10 +27,14 @@ import com.facebook.react.bridge.ReactNoCrashSoftException;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.RetryableMountingLayerException;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.common.mapbuffer.MapBuffer;
@@ -53,7 +57,10 @@ import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.events.EventCategoryDef;
import com.facebook.systrace.Systrace;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
@@ -96,6 +103,11 @@ public class SurfaceMountingManager {
// This is null *until* StopSurface is called.
private SparseArrayCompat<Object> mTagSetForStoppedSurface;
// This is to make sure direct manipulation result will not be overridden by React update.
@ThreadConfined(UI)
private final SparseArrayCompat<Map<String, Object>> mTagToSynchronousMountProps =
new SparseArrayCompat<>();
private final int mSurfaceId;
public SurfaceMountingManager(
@@ -682,13 +694,110 @@ public class SurfaceMountingManager {
}
}
private static void overridePropsReadableMap(
Map<String, Object> patchMap, WritableMap outputReadableMap) {
for (Map.Entry<String, Object> entry : patchMap.entrySet()) {
String propKey = entry.getKey();
if (outputReadableMap.hasKey(propKey)) {
Object propValue = entry.getValue();
if (propKey.equals("transform")) {
assert (outputReadableMap.getType(propKey) == ReadableType.Array
&& propValue instanceof ArrayList);
WritableArray array = new WritableNativeArray();
for (Object item : (ArrayList<?>) propValue) {
if (item instanceof HashMap) {
WritableNativeMap itemMap = new WritableNativeMap();
for (Map.Entry<String, Object> itemEntry :
((HashMap<String, Object>) item).entrySet()) {
if (itemEntry.getValue() instanceof String) {
itemMap.putString(itemEntry.getKey(), (String) itemEntry.getValue());
} else if (itemEntry.getValue() instanceof Number) {
itemMap.putDouble(
itemEntry.getKey(), ((Number) itemEntry.getValue()).doubleValue());
}
}
array.pushMap(itemMap);
}
}
outputReadableMap.putArray(propKey, array);
} else if (propKey.equals("opacity")) {
assert (outputReadableMap.getType(propKey) == ReadableType.Number
&& propValue instanceof Number);
outputReadableMap.putDouble(propKey, ((Number) propValue).doubleValue());
}
}
}
}
private static Map<String, Object> getHashMapFromPropsReadableMap(ReadableMap readableMap) {
HashMap<String, Object> outputMap = new HashMap<>();
Iterator<Map.Entry<String, Object>> iter = readableMap.getEntryIterator();
while (iter.hasNext()) {
Map.Entry<String, Object> entry = iter.next();
String propKey = entry.getKey();
Object propValue = entry.getValue();
if (propKey.equals("transform") && propValue instanceof ReadableArray) {
ArrayList<HashMap<String, Object>> arrayList = new ArrayList<>();
for (int i = 0; i < ((ReadableArray) propValue).size(); i++) {
ReadableMap map = ((ReadableArray) propValue).getMap(i);
if (map != null) {
arrayList.add(map.toHashMap());
}
}
outputMap.put(propKey, arrayList);
} else if (propKey.equals("opacity") && propValue instanceof Number) {
outputMap.put(propKey, ((Number) propValue).doubleValue());
}
}
return outputMap;
}
public void storeSynchronousMountPropsOverride(int reactTag, ReadableMap props) {
if (ReactNativeFeatureFlags.overrideBySynchronousMountPropsAtMountingAndroid()) {
Map<String, Object> propsMap = getHashMapFromPropsReadableMap(props);
if (mTagToSynchronousMountProps.containsKey(reactTag)) {
Map<String, Object> mergedPropsMap =
Assertions.assertNotNull(mTagToSynchronousMountProps.get(reactTag));
mergedPropsMap.putAll(propsMap);
mTagToSynchronousMountProps.put(reactTag, mergedPropsMap);
} else {
mTagToSynchronousMountProps.put(reactTag, propsMap);
}
}
}
public void updatePropsSynchronously(int reactTag, ReadableMap props) {
updateProps(reactTag, props, true);
}
public void updateProps(int reactTag, ReadableMap props) {
updateProps(reactTag, props, false);
}
@UiThread
private void updateProps(
int reactTag, ReadableMap props, Boolean shouldSkipSynchronousMountPropsOverride) {
if (isStopped()) {
return;
}
ViewState viewState = getViewState(reactTag);
viewState.mCurrentProps = new ReactStylesDiffMap(props);
if (ReactNativeFeatureFlags.overrideBySynchronousMountPropsAtMountingAndroid()
&& !shouldSkipSynchronousMountPropsOverride
&& mTagToSynchronousMountProps.containsKey(reactTag)) {
WritableMap modifiedProps = new WritableNativeMap();
modifiedProps.merge(props);
Map<String, Object> directPropsMap =
Assertions.assertNotNull(mTagToSynchronousMountProps.get(reactTag));
overridePropsReadableMap(directPropsMap, modifiedProps);
viewState.mCurrentProps = new ReactStylesDiffMap(modifiedProps);
} else {
viewState.mCurrentProps = new ReactStylesDiffMap(props);
}
View view = viewState.mView;
if (view == null) {
@@ -1057,6 +1166,11 @@ public class SurfaceMountingManager {
return;
}
if (ReactNativeFeatureFlags.overrideBySynchronousMountPropsAtMountingAndroid()
&& mTagToSynchronousMountProps.containsKey(reactTag)) {
mTagToSynchronousMountProps.remove(reactTag);
}
ViewState viewState = getNullableViewState(reactTag);
if (viewState == 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<<92a6edded037a504fc1c2c8ae88deae1>>
* @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.
*/
@@ -324,6 +330,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun hideOffscreenVirtualViewsOnIOS(): Boolean = accessor.hideOffscreenVirtualViewsOnIOS()
/**
* Override props at mounting with synchronously mounted (i.e. direct manipulation) props from Native Animated.
*/
@JvmStatic
public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = accessor.overrideBySynchronousMountPropsAtMountingAndroid()
/**
* Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes.
*/
@@ -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<<ebbc6602fc8e3fb4c510bbd47361a7f0>>
* @generated SignedSource<<ea5133af611c4d1e7e70155a3a74492d>>
*/
/**
@@ -65,10 +65,12 @@ 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
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
private var perfMonitorV2EnabledCache: Boolean? = null
private var preparedTextCacheSizeCache: Double? = null
private var preventShadowTreeCommitExhaustionCache: Boolean? = null
@@ -495,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) {
@@ -531,6 +542,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean {
var cached = overrideBySynchronousMountPropsAtMountingAndroidCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.overrideBySynchronousMountPropsAtMountingAndroid()
overrideBySynchronousMountPropsAtMountingAndroidCache = cached
}
return cached
}
override fun perfMonitorV2Enabled(): Boolean {
var cached = perfMonitorV2EnabledCache
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<<4410628511f112f3eef22434a05fa757>>
* @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
@@ -126,6 +128,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun hideOffscreenVirtualViewsOnIOS(): Boolean
@DoNotStrip @JvmStatic public external fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun perfMonitorV2Enabled(): Boolean
@DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double
@@ -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<<411732d441bacbef37c3474b9041202c>>
* @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
@@ -121,6 +123,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun hideOffscreenVirtualViewsOnIOS(): Boolean = false
override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = false
override fun perfMonitorV2Enabled(): Boolean = false
override fun preparedTextCacheSize(): Double = 200.0
@@ -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<<2f65e0e9066a8c2c35c44ea7c73dbedc>>
* @generated SignedSource<<f3798eada96337cf98715fa580823b30>>
*/
/**
@@ -69,10 +69,12 @@ 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
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
private var perfMonitorV2EnabledCache: Boolean? = null
private var preparedTextCacheSizeCache: Double? = null
private var preventShadowTreeCommitExhaustionCache: Boolean? = null
@@ -544,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) {
@@ -584,6 +596,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean {
var cached = overrideBySynchronousMountPropsAtMountingAndroidCache
if (cached == null) {
cached = currentProvider.overrideBySynchronousMountPropsAtMountingAndroid()
accessedFeatureFlags.add("overrideBySynchronousMountPropsAtMountingAndroid")
overrideBySynchronousMountPropsAtMountingAndroidCache = cached
}
return cached
}
override fun perfMonitorV2Enabled(): Boolean {
var cached = perfMonitorV2EnabledCache
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<<e97601660cfd4f614ac934ba20ca4635>>
* @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
@@ -121,6 +123,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun hideOffscreenVirtualViewsOnIOS(): Boolean
@DoNotStrip public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
@DoNotStrip public fun perfMonitorV2Enabled(): Boolean
@DoNotStrip public fun preparedTextCacheSize(): Double
@@ -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<<f9c4f8d97edff1b016873b0a6121b76b>>
* @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");
@@ -333,6 +339,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}
bool overrideBySynchronousMountPropsAtMountingAndroid() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("overrideBySynchronousMountPropsAtMountingAndroid");
return method(javaProvider_);
}
bool perfMonitorV2Enabled() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("perfMonitorV2Enabled");
@@ -682,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();
@@ -702,6 +719,11 @@ bool JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS(
return ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS();
}
bool JReactNativeFeatureFlagsCxxInterop::overrideBySynchronousMountPropsAtMountingAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid();
}
bool JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::perfMonitorV2Enabled();
@@ -968,6 +990,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"enableVirtualViewWindowFocusDetection",
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection),
makeNativeMethod(
"enableWebPerformanceAPIsByDefault",
JReactNativeFeatureFlagsCxxInterop::enableWebPerformanceAPIsByDefault),
makeNativeMethod(
"fixMappingOfEventPrioritiesBetweenFabricAndReact",
JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),
@@ -980,6 +1005,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"hideOffscreenVirtualViewsOnIOS",
JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS),
makeNativeMethod(
"overrideBySynchronousMountPropsAtMountingAndroid",
JReactNativeFeatureFlagsCxxInterop::overrideBySynchronousMountPropsAtMountingAndroid),
makeNativeMethod(
"perfMonitorV2Enabled",
JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled),
@@ -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<<6a98f8398948f8d56e51d3eff19c5d05>>
* @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>);
@@ -177,6 +180,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool hideOffscreenVirtualViewsOnIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool overrideBySynchronousMountPropsAtMountingAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool perfMonitorV2Enabled(
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()
@@ -15,16 +15,16 @@ namespace facebook::react::jsinspector_modern {
namespace {
// Vendored from Folly
// https://github.com/facebook/folly/blob/v2024.07.08.00/folly/detail/base64_detail/Base64Scalar.h
constexpr char kBase64Charset[] =
constexpr std::string_view kBase64Charset =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
constexpr char kBase64URLCharset[] =
constexpr std::string_view kBase64URLCharset =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
template <bool isURL>
struct Base64ScalarImpl {
static constexpr const char* kCharset =
isURL ? kBase64URLCharset : kBase64Charset;
isURL ? kBase64URLCharset.data() : kBase64Charset.data();
// 0, 1 or 2 bytes
static constexpr char* encodeTail(const char* f, const char* l, char* o) {
@@ -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<<5bd932f1d52596dad6ea86a2674170ff>>
* @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();
}
@@ -222,6 +226,10 @@ bool ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS() {
return getAccessor().hideOffscreenVirtualViewsOnIOS();
}
bool ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid() {
return getAccessor().overrideBySynchronousMountPropsAtMountingAndroid();
}
bool ReactNativeFeatureFlags::perfMonitorV2Enabled() {
return getAccessor().perfMonitorV2Enabled();
}
@@ -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<<3cde1e9bcf234515551ba57ecf02e3a7>>
* @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.
*/
@@ -284,6 +289,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool hideOffscreenVirtualViewsOnIOS();
/**
* Override props at mounting with synchronously mounted (i.e. direct manipulation) props from Native Animated.
*/
RN_EXPORT static bool overrideBySynchronousMountPropsAtMountingAndroid();
/**
* Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes.
*/
@@ -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<<bf7bb959d851abb8cd98a2eb3fa43923>>
* @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;
@@ -911,6 +929,24 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingAndroid() {
auto flagValue = overrideBySynchronousMountPropsAtMountingAndroid_.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(50, "overrideBySynchronousMountPropsAtMountingAndroid");
flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid();
overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() {
auto flagValue = perfMonitorV2Enabled_.load();
@@ -920,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(49, "perfMonitorV2Enabled");
markFlagAsAccessed(51, "perfMonitorV2Enabled");
flagValue = currentProvider_->perfMonitorV2Enabled();
perfMonitorV2Enabled_ = flagValue;
@@ -938,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(50, "preparedTextCacheSize");
markFlagAsAccessed(52, "preparedTextCacheSize");
flagValue = currentProvider_->preparedTextCacheSize();
preparedTextCacheSize_ = flagValue;
@@ -956,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(51, "preventShadowTreeCommitExhaustion");
markFlagAsAccessed(53, "preventShadowTreeCommitExhaustion");
flagValue = currentProvider_->preventShadowTreeCommitExhaustion();
preventShadowTreeCommitExhaustion_ = flagValue;
@@ -974,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(52, "shouldPressibilityUseW3CPointerEventsForHover");
markFlagAsAccessed(54, "shouldPressibilityUseW3CPointerEventsForHover");
flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover();
shouldPressibilityUseW3CPointerEventsForHover_ = flagValue;
@@ -992,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(53, "skipActivityIdentityAssertionOnHostPause");
markFlagAsAccessed(55, "skipActivityIdentityAssertionOnHostPause");
flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause();
skipActivityIdentityAssertionOnHostPause_ = flagValue;
@@ -1010,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(54, "sweepActiveTouchOnChildNativeGesturesAndroid");
markFlagAsAccessed(56, "sweepActiveTouchOnChildNativeGesturesAndroid");
flagValue = currentProvider_->sweepActiveTouchOnChildNativeGesturesAndroid();
sweepActiveTouchOnChildNativeGesturesAndroid_ = flagValue;
@@ -1028,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(55, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(57, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -1046,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(56, "updateRuntimeShadowNodeReferencesOnCommit");
markFlagAsAccessed(58, "updateRuntimeShadowNodeReferencesOnCommit");
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
@@ -1064,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(57, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(59, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -1082,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(58, "useFabricInterop");
markFlagAsAccessed(60, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -1100,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(59, "useNativeEqualsInNativeReadableArrayAndroid");
markFlagAsAccessed(61, "useNativeEqualsInNativeReadableArrayAndroid");
flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid();
useNativeEqualsInNativeReadableArrayAndroid_ = flagValue;
@@ -1118,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(60, "useNativeTransformHelperAndroid");
markFlagAsAccessed(62, "useNativeTransformHelperAndroid");
flagValue = currentProvider_->useNativeTransformHelperAndroid();
useNativeTransformHelperAndroid_ = flagValue;
@@ -1136,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(61, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(63, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -1154,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(62, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(64, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -1172,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(63, "useRawPropsJsiValue");
markFlagAsAccessed(65, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -1190,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(64, "useShadowNodeStateOnClone");
markFlagAsAccessed(66, "useShadowNodeStateOnClone");
flagValue = currentProvider_->useShadowNodeStateOnClone();
useShadowNodeStateOnClone_ = flagValue;
@@ -1208,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(65, "useTurboModuleInterop");
markFlagAsAccessed(67, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -1226,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(66, "useTurboModules");
markFlagAsAccessed(68, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -1244,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(67, "virtualViewHysteresisRatio");
markFlagAsAccessed(69, "virtualViewHysteresisRatio");
flagValue = currentProvider_->virtualViewHysteresisRatio();
virtualViewHysteresisRatio_ = flagValue;
@@ -1262,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(68, "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<<a449e9cf8f14bb7381d9779c764d0d7c>>
* @generated SignedSource<<17f7a8577d05b191010622fb58ba27f8>>
*/
/**
@@ -77,10 +77,12 @@ class ReactNativeFeatureFlagsAccessor {
bool enableVirtualViewDebugFeatures();
bool enableVirtualViewRenderState();
bool enableVirtualViewWindowFocusDetection();
bool enableWebPerformanceAPIsByDefault();
bool fixMappingOfEventPrioritiesBetweenFabricAndReact();
bool fuseboxEnabledRelease();
bool fuseboxNetworkInspectionEnabled();
bool hideOffscreenVirtualViewsOnIOS();
bool overrideBySynchronousMountPropsAtMountingAndroid();
bool perfMonitorV2Enabled();
double preparedTextCacheSize();
bool preventShadowTreeCommitExhaustion();
@@ -112,7 +114,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 69> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 71> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> cdpInteractionMetricsEnabled_;
@@ -159,10 +161,12 @@ 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_;
std::atomic<std::optional<bool>> hideOffscreenVirtualViewsOnIOS_;
std::atomic<std::optional<bool>> overrideBySynchronousMountPropsAtMountingAndroid_;
std::atomic<std::optional<bool>> perfMonitorV2Enabled_;
std::atomic<std::optional<double>> preparedTextCacheSize_;
std::atomic<std::optional<bool>> preventShadowTreeCommitExhaustion_;
@@ -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<<6d8adaa4b960407540afb1d6e42a3840>>
* @generated SignedSource<<f387394359fc15af1ecad288f08fefe7>>
*/
/**
@@ -207,6 +207,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool enableWebPerformanceAPIsByDefault() override {
return false;
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
return false;
}
@@ -223,6 +227,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool overrideBySynchronousMountPropsAtMountingAndroid() override {
return false;
}
bool perfMonitorV2Enabled() 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<<ccd274f2ece9c85f23dd87e74d446ecb>>
* @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()) {
@@ -486,6 +495,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::hideOffscreenVirtualViewsOnIOS();
}
bool overrideBySynchronousMountPropsAtMountingAndroid() override {
auto value = values_["overrideBySynchronousMountPropsAtMountingAndroid"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::overrideBySynchronousMountPropsAtMountingAndroid();
}
bool perfMonitorV2Enabled() override {
auto value = values_["perfMonitorV2Enabled"];
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<<07b25b19a265e8afe53eeeffade4dfc0>>
* @generated SignedSource<<d8b57edf1ba256965238058533a2ea7d>>
*/
/**
@@ -70,10 +70,12 @@ 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;
virtual bool hideOffscreenVirtualViewsOnIOS() = 0;
virtual bool overrideBySynchronousMountPropsAtMountingAndroid() = 0;
virtual bool perfMonitorV2Enabled() = 0;
virtual double preparedTextCacheSize() = 0;
virtual bool preventShadowTreeCommitExhaustion() = 0;
@@ -51,7 +51,7 @@ std::vector<const RCTMethodInfo *> getMethodInfos(Class moduleClass)
std::vector<const RCTMethodInfo *> methodInfos;
Class cls = moduleClass;
while (cls && cls != [NSObject class] && cls != [NSProxy class]) {
while ((cls != nullptr) && cls != [NSObject class] && cls != [NSProxy class]) {
unsigned int methodCount;
Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
@@ -482,7 +482,7 @@ void ObjCInteropTurboModule::setInvocationArg(
return;
}
if (arg) {
if (arg != nullptr) {
[retainedObjectsForInvocation addObject:arg];
}
[inv setArgument:&arg atIndex:(index) + 2];
@@ -496,7 +496,7 @@ void ObjCInteropTurboModule::setInvocationArg(
typeInvocation.target = [RCTConvert class];
void *returnValue = malloc(typeSignature.methodReturnLength);
if (!returnValue) {
if (returnValue == nullptr) {
// CWE - 391 : Unchecked error condition
// https://www.cvedetails.com/cwe-details/391/Unchecked-Error-Condition.html
// https://eli.thegreenplace.net/2009/10/30/handling-out-of-memory-conditions-in-c
@@ -519,7 +519,7 @@ void ObjCInteropTurboModule::setInvocationArg(
* RCTModuleMethod doesn't actually call into RCTConvert in this case.
*/
id arg = [objCArg copy];
if (arg) {
if (arg != nullptr) {
[retainedObjectsForInvocation addObject:arg];
}
[inv setArgument:&arg atIndex:(index) + 2];
@@ -537,7 +537,7 @@ void ObjCInteropTurboModule::setInvocationArg(
RCTResponseSenderBlock arg =
(RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
if (arg) {
if (arg != nullptr) {
[retainedObjectsForInvocation addObject:arg];
}
[inv setArgument:&arg atIndex:(index) + 2];
@@ -59,7 +59,7 @@ static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *va
static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
{
return jsi::String::createFromUtf8(runtime, [value UTF8String] ? [value UTF8String] : "");
return jsi::String::createFromUtf8(runtime, ([value UTF8String] != nullptr) ? [value UTF8String] : "");
}
static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
@@ -124,7 +124,7 @@ static NSArray *convertJSIArrayToNSArray(
for (size_t i = 0; i < size; i++) {
// Insert kCFNull when it's `undefined` value to preserve the indices.
id convertedObject = convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker, useNSNull);
[result addObject:convertedObject ? convertedObject : (id)kCFNull];
[result addObject:(convertedObject != nullptr) ? convertedObject : (id)kCFNull];
}
return result;
}
@@ -142,7 +142,7 @@ static NSDictionary *convertJSIObjectToNSDictionary(
jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
NSString *k = convertJSIStringToNSString(runtime, name);
id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker, useNSNull);
if (v) {
if (v != nullptr) {
result[k] = v;
}
}
@@ -252,7 +252,7 @@ static jsi::Value convertJSErrorDetailsToJSRuntimeError(jsi::Runtime &runtime, N
jsi::Value
ObjCTurboModule::createPromise(jsi::Runtime &runtime, const std::string &methodName, PromiseInvocationBlock invoke)
{
if (!invoke) {
if (invoke == nullptr) {
return jsi::Value::undefined();
}
@@ -388,7 +388,7 @@ id ObjCTurboModule::performMethodInvocation(
void (^block)() = ^{
id<RCTBridgeModule> strongModule = weakModule;
if (!strongModule) {
if (strongModule == nullptr) {
return;
}
@@ -457,7 +457,7 @@ void ObjCTurboModule::performVoidMethodInvocation(
void (^block)() = ^{
id<RCTBridgeModule> strongModule = weakModule;
if (!strongModule) {
if (strongModule == nullptr) {
return;
}
@@ -560,14 +560,14 @@ jsi::Value ObjCTurboModule::convertReturnIdToJSIValue(
*/
NSString *ObjCTurboModule::getArgumentTypeName(jsi::Runtime &runtime, NSString *methodName, int argIndex)
{
if (!methodArgumentTypeNames_) {
if (methodArgumentTypeNames_ == nullptr) {
NSMutableDictionary<NSString *, NSArray<NSString *> *> *methodArgumentTypeNames = [NSMutableDictionary new];
unsigned int numberOfMethods;
Class cls = [instance_ class];
Method *methods = class_copyMethodList(object_getClass(cls), &numberOfMethods);
if (methods) {
if (methods != nullptr) {
for (unsigned int i = 0; i < numberOfMethods; i++) {
SEL s = method_getName(methods[i]);
NSString *mName = NSStringFromSelector(s);
@@ -597,7 +597,7 @@ NSString *ObjCTurboModule::getArgumentTypeName(jsi::Runtime &runtime, NSString *
methodArgumentTypeNames_ = methodArgumentTypeNames;
}
if (methodArgumentTypeNames_[methodName]) {
if (methodArgumentTypeNames_[methodName] != nullptr) {
assert([methodArgumentTypeNames_[methodName] count] > argIndex);
return methodArgumentTypeNames_[methodName][argIndex];
}
@@ -656,7 +656,7 @@ void ObjCTurboModule::setInvocationArg(
*/
BOOL enableModuleArgumentNSNullConversionIOS = ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
id objCArg = convertJSIValueToObjCObject(runtime, arg, jsInvoker_, enableModuleArgumentNSNullConversionIOS);
if (objCArg) {
if (objCArg != nullptr) {
NSString *methodNameNSString = @(methodName);
/**
@@ -678,7 +678,7 @@ void ObjCTurboModule::setInvocationArg(
}
[inv setArgument:(void *)&convertedObjCArg atIndex:i + 2];
if (convertedObjCArg) {
if (convertedObjCArg != nullptr) {
[retainedObjectsForInvocation addObject:convertedObjCArg];
}
return;
@@ -708,7 +708,7 @@ void ObjCTurboModule::setInvocationArg(
* Insert converted args unmodified.
*/
[inv setArgument:(void *)&objCArg atIndex:i + 2];
if (objCArg) {
if (objCArg != nullptr) {
[retainedObjectsForInvocation addObject:objCArg];
}
}
@@ -848,7 +848,7 @@ jsi::Value ObjCTurboModule::invokeObjCMethod(
BOOL ObjCTurboModule::hasMethodArgConversionSelector(NSString *methodName, size_t argIndex)
{
return methodArgConversionSelectors_ && methodArgConversionSelectors_[methodName] &&
return (methodArgConversionSelectors_ != nullptr) && (methodArgConversionSelectors_[methodName] != nullptr) &&
![methodArgConversionSelectors_[methodName][argIndex] isEqual:(id)kCFNull];
}
@@ -860,11 +860,11 @@ SEL ObjCTurboModule::getMethodArgConversionSelector(NSString *methodName, size_t
void ObjCTurboModule::setMethodArgConversionSelector(NSString *methodName, size_t argIndex, NSString *fnName)
{
if (!methodArgConversionSelectors_) {
if (methodArgConversionSelectors_ == nullptr) {
methodArgConversionSelectors_ = [NSMutableDictionary new];
}
if (!methodArgConversionSelectors_[methodName]) {
if (methodArgConversionSelectors_[methodName] == nullptr) {
auto metaData = methodMap_.at([methodName UTF8String]);
auto argCount = metaData.argCount;
@@ -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);
@@ -50,5 +50,6 @@ Pod::Spec.new do |s|
s.dependency "React-featureflagsnativemodule"
s.dependency "React-microtasksnativemodule"
s.dependency "React-idlecallbacksnativemodule"
s.dependency "React-webperformancenativemodule"
add_dependency(s, "React-RCTFBReactNativeSpec")
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<<348005db0ceee698cd7c33f29bcf85a6>>
* @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();
@@ -289,6 +294,11 @@ bool NativeReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS(
return ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS();
}
bool NativeReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid();
}
bool NativeReactNativeFeatureFlags::perfMonitorV2Enabled(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::perfMonitorV2Enabled();
@@ -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<<a27c4788a4b87366ef1e3ee03da53ab6>>
* @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);
@@ -134,6 +136,8 @@ class NativeReactNativeFeatureFlags
bool hideOffscreenVirtualViewsOnIOS(jsi::Runtime& runtime);
bool overrideBySynchronousMountPropsAtMountingAndroid(jsi::Runtime& runtime);
bool perfMonitorV2Enabled(jsi::Runtime& runtime);
double preparedTextCacheSize(jsi::Runtime& runtime);
@@ -136,14 +136,14 @@ RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, getValue : (double)x y : (NS
{
return @{
@"x" : @(x),
@"y" : y ? y : [NSNull null],
@"z" : z ? z : [NSNull null],
@"y" : (y != nullptr) ? y : [NSNull null],
@"z" : (z != nullptr) ? z : [NSNull null],
};
}
RCT_EXPORT_METHOD(getValueWithCallback : (RCTResponseSenderBlock)callback)
{
if (!callback) {
if (callback == nullptr) {
return;
}
callback(@[ @"value from callback!" ]);
@@ -154,7 +154,7 @@ RCT_EXPORT_METHOD(getValueWithPromise
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
if (!resolve || !reject) {
if ((resolve == nullptr) || (reject == nullptr)) {
return;
}
@@ -136,14 +136,14 @@ RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, getValue : (double)x y : (NS
{
return @{
@"x" : @(x),
@"y" : y ? y : [NSNull null],
@"z" : z ? z : [NSNull null],
@"y" : (y != nullptr) ? y : [NSNull null],
@"z" : (z != nullptr) ? z : [NSNull null],
};
}
RCT_EXPORT_METHOD(getValueWithCallback : (RCTResponseSenderBlock)callback)
{
if (!callback) {
if (callback == nullptr) {
return;
}
callback(@[ @"value from callback!" ]);
@@ -154,7 +154,7 @@ RCT_EXPORT_METHOD(getValueWithPromise
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
if (!resolve || !reject) {
if ((resolve == nullptr) || (reject == nullptr)) {
return;
}
@@ -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,58 @@
# 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"
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
@@ -742,7 +742,8 @@ folly::dynamic NativeAnimatedNodesManager::managedProps(
if (const auto node = getAnimatedNode<PropsAnimatedNode>(iter->second)) {
return node->props();
}
} else {
} else if (!ReactNativeFeatureFlags::
overrideBySynchronousMountPropsAtMountingAndroid()) {
std::lock_guard<std::mutex> lockUnsyncedDirectViewProps(
unsyncedDirectViewPropsMutex_);
if (auto it = unsyncedDirectViewProps_.find(tag);
@@ -761,7 +762,8 @@ bool NativeAnimatedNodesManager::hasManagedProps() const noexcept {
return true;
}
}
{
if (!ReactNativeFeatureFlags::
overrideBySynchronousMountPropsAtMountingAndroid()) {
std::lock_guard<std::mutex> lock(unsyncedDirectViewPropsMutex_);
if (!unsyncedDirectViewProps_.empty()) {
return true;
@@ -771,10 +773,13 @@ bool NativeAnimatedNodesManager::hasManagedProps() const noexcept {
}
void NativeAnimatedNodesManager::onManagedPropsRemoved(Tag tag) noexcept {
std::lock_guard<std::mutex> lock(unsyncedDirectViewPropsMutex_);
if (auto iter = unsyncedDirectViewProps_.find(tag);
iter != unsyncedDirectViewProps_.end()) {
unsyncedDirectViewProps_.erase(iter);
if (!ReactNativeFeatureFlags::
overrideBySynchronousMountPropsAtMountingAndroid()) {
std::lock_guard<std::mutex> lock(unsyncedDirectViewPropsMutex_);
if (auto iter = unsyncedDirectViewProps_.find(tag);
iter != unsyncedDirectViewProps_.end()) {
unsyncedDirectViewProps_.erase(iter);
}
}
}
@@ -828,7 +833,8 @@ void NativeAnimatedNodesManager::schedulePropsCommit(
mergeObjects(updateViewPropsDirect_[viewTag], props);
} else if (!layoutStyleUpdated && directManipulationCallback_ != nullptr) {
mergeObjects(updateViewPropsDirect_[viewTag], props);
{
if (!ReactNativeFeatureFlags::
overrideBySynchronousMountPropsAtMountingAndroid()) {
std::lock_guard<std::mutex> lock(unsyncedDirectViewPropsMutex_);
mergeObjects(unsyncedDirectViewProps_[viewTag], props);
}
@@ -402,79 +402,79 @@ inline void fromRawValue(
inline std::string toString(const FontVariant& fontVariant) {
auto result = std::string{};
auto separator = std::string{", "};
if ((int)fontVariant & (int)FontVariant::SmallCaps) {
if (((int)fontVariant & (int)FontVariant::SmallCaps) != 0) {
result += "small-caps" + separator;
}
if ((int)fontVariant & (int)FontVariant::OldstyleNums) {
if (((int)fontVariant & (int)FontVariant::OldstyleNums) != 0) {
result += "oldstyle-nums" + separator;
}
if ((int)fontVariant & (int)FontVariant::LiningNums) {
if (((int)fontVariant & (int)FontVariant::LiningNums) != 0) {
result += "lining-nums" + separator;
}
if ((int)fontVariant & (int)FontVariant::TabularNums) {
if (((int)fontVariant & (int)FontVariant::TabularNums) != 0) {
result += "tabular-nums" + separator;
}
if ((int)fontVariant & (int)FontVariant::ProportionalNums) {
if (((int)fontVariant & (int)FontVariant::ProportionalNums) != 0) {
result += "proportional-nums" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticOne) {
if (((int)fontVariant & (int)FontVariant::StylisticOne) != 0) {
result += "stylistic-one" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticTwo) {
if (((int)fontVariant & (int)FontVariant::StylisticTwo) != 0) {
result += "stylistic-two" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticThree) {
if (((int)fontVariant & (int)FontVariant::StylisticThree) != 0) {
result += "stylistic-three" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticFour) {
if (((int)fontVariant & (int)FontVariant::StylisticFour) != 0) {
result += "stylistic-four" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticFive) {
if (((int)fontVariant & (int)FontVariant::StylisticFive) != 0) {
result += "stylistic-five" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticSix) {
if (((int)fontVariant & (int)FontVariant::StylisticSix) != 0) {
result += "stylistic-six" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticSeven) {
if (((int)fontVariant & (int)FontVariant::StylisticSeven) != 0) {
result += "stylistic-seven" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticEight) {
if (((int)fontVariant & (int)FontVariant::StylisticEight) != 0) {
result += "stylistic-eight" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticNine) {
if (((int)fontVariant & (int)FontVariant::StylisticNine) != 0) {
result += "stylistic-nine" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticTen) {
if (((int)fontVariant & (int)FontVariant::StylisticTen) != 0) {
result += "stylistic-ten" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticEleven) {
if (((int)fontVariant & (int)FontVariant::StylisticEleven) != 0) {
result += "stylistic-eleven" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticTwelve) {
if (((int)fontVariant & (int)FontVariant::StylisticTwelve) != 0) {
result += "stylistic-twelve" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticThirteen) {
if (((int)fontVariant & (int)FontVariant::StylisticThirteen) != 0) {
result += "stylistic-thirteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticFourteen) {
if (((int)fontVariant & (int)FontVariant::StylisticFourteen) != 0) {
result += "stylistic-fourteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticFifteen) {
if (((int)fontVariant & (int)FontVariant::StylisticFifteen) != 0) {
result += "stylistic-fifteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticSixteen) {
if (((int)fontVariant & (int)FontVariant::StylisticSixteen) != 0) {
result += "stylistic-sixteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticSeventeen) {
if (((int)fontVariant & (int)FontVariant::StylisticSeventeen) != 0) {
result += "stylistic-seventeen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticEighteen) {
if (((int)fontVariant & (int)FontVariant::StylisticEighteen) != 0) {
result += "stylistic-eighteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticNineteen) {
if (((int)fontVariant & (int)FontVariant::StylisticNineteen) != 0) {
result += "stylistic-nineteen" + separator;
}
if ((int)fontVariant & (int)FontVariant::StylisticTwenty) {
if (((int)fontVariant & (int)FontVariant::StylisticTwenty) != 0) {
result += "stylistic-twenty" + separator;
}
@@ -63,13 +63,13 @@ static Class getViewManagerFromComponentName(const std::string &componentName)
// 1. Try to get the manager with the RCT prefix.
auto rctViewManagerName = "RCT" + viewManagerName;
Class viewManagerClass = NSClassFromString(RCTNSStringFromString(rctViewManagerName));
if (viewManagerClass) {
if (viewManagerClass != nullptr) {
return viewManagerClass;
}
// 2. Try to get the manager without the prefix.
viewManagerClass = NSClassFromString(RCTNSStringFromString(viewManagerName));
if (viewManagerClass) {
if (viewManagerClass != nullptr) {
return viewManagerClass;
}
@@ -54,7 +54,7 @@ class AndroidTextInputComponentDescriptor final
->getMethod<jboolean(jint, jfloatArray)>("getThemeData");
if (getThemeData(
fabricUIManager, surfaceId, defaultTextInputPaddingArray)) {
fabricUIManager, surfaceId, defaultTextInputPaddingArray) != 0u) {
jfloat* defaultTextInputPadding =
env->GetFloatArrayElements(defaultTextInputPaddingArray, nullptr);
theme.start = defaultTextInputPadding[0];
@@ -310,7 +310,7 @@ static void updateBorderColorPropValue(
const std::optional<SharedColor>& newColor,
const std::optional<SharedColor>& oldColor) {
if (newColor != oldColor) {
result[propName] = *newColor.value_or(SharedColor());
result[propName] = newColor.has_value() ? *newColor.value() : NULL;
}
}

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