react-native-tvos 0.85.0-0rc5 → 0.85.3-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
  2. package/Libraries/Components/ScrollView/ScrollView.d.ts +7 -0
  3. package/Libraries/Components/ScrollView/ScrollView.js +6 -0
  4. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -0
  5. package/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js +1 -0
  6. package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +5 -1
  7. package/Libraries/Components/TextInput/TextInput.flow.js +1 -0
  8. package/Libraries/Core/ReactNativeVersion.js +2 -2
  9. package/Libraries/Utilities/HMRClient.js +28 -1
  10. package/README.md +52 -0
  11. package/React/Base/RCTVersion.m +2 -2
  12. package/React/CoreModules/RCTDevLoadingView.mm +17 -0
  13. package/React/CoreModules/RCTJscSafeUrl+Internal.h +23 -0
  14. package/React/CoreModules/RCTJscSafeUrl.mm +38 -0
  15. package/React/CoreModules/RCTRedBox+Internal.h +42 -0
  16. package/React/CoreModules/RCTRedBox.mm +30 -471
  17. package/React/CoreModules/RCTRedBox2AnsiParser+Internal.h +22 -0
  18. package/React/CoreModules/RCTRedBox2AnsiParser.mm +55 -0
  19. package/React/CoreModules/RCTRedBox2Controller+Internal.h +34 -0
  20. package/React/CoreModules/RCTRedBox2Controller.mm +764 -0
  21. package/React/CoreModules/RCTRedBox2ErrorParser+Internal.h +46 -0
  22. package/React/CoreModules/RCTRedBox2ErrorParser.mm +57 -0
  23. package/React/CoreModules/RCTRedBoxController+Internal.h +31 -0
  24. package/React/CoreModules/RCTRedBoxController.mm +447 -0
  25. package/React/CoreModules/RCTRedBoxHMRClient+Internal.h +26 -0
  26. package/React/CoreModules/RCTRedBoxHMRClient.mm +125 -0
  27. package/React/CoreModules/React-CoreModules.podspec +1 -0
  28. package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
  29. package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
  30. package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +40 -0
  31. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.h +1 -0
  32. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +78 -0
  33. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +32 -6
  34. package/React/Views/ScrollView/RCTScrollViewManager.m +1 -0
  35. package/ReactAndroid/build.gradle.kts +2 -0
  36. package/ReactAndroid/gradle.properties +1 -1
  37. package/ReactAndroid/hermes-engine/build.gradle.kts +17 -0
  38. package/ReactAndroid/publish.gradle +20 -46
  39. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
  40. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +1 -1
  41. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +127 -26
  42. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +31 -1
  43. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +51 -1
  44. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +11 -1
  45. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +12 -2
  46. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +56 -1
  47. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt +5 -1
  48. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +11 -1
  49. package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
  50. package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +8 -0
  51. package/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.kt +2 -0
  52. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +2 -2
  53. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +50 -10
  54. package/ReactAndroid/src/main/java/com/facebook/react/views/common/UiModeUtils.kt +20 -0
  55. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +57 -8
  56. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt +5 -0
  57. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +48 -2
  58. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt +5 -0
  59. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +28 -3
  60. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt +5 -0
  61. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSubmitEditingEvent.kt +6 -1
  62. package/ReactAndroid/src/main/jni/CMakeLists.txt +7 -0
  63. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
  64. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
  65. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +71 -1
  66. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +16 -1
  67. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +14 -0
  68. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +18 -4
  69. package/ReactCommon/React-Fabric.podspec +7 -0
  70. package/ReactCommon/cxxreact/ReactNativeVersion.h +3 -3
  71. package/ReactCommon/jsinspector-modern/HostAgent.cpp +36 -0
  72. package/ReactCommon/jsinspector-modern/HostTarget.cpp +7 -1
  73. package/ReactCommon/jsinspector-modern/HostTarget.h +25 -0
  74. package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +1 -1
  75. package/ReactCommon/jsinspector-modern/HostTargetTracing.h +4 -4
  76. package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
  77. package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
  78. package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
  79. package/ReactCommon/jsinspector-modern/RuntimeAgent.cpp +19 -0
  80. package/ReactCommon/jsinspector-modern/RuntimeAgent.h +7 -0
  81. package/ReactCommon/jsinspector-modern/RuntimeTarget.cpp +33 -0
  82. package/ReactCommon/jsinspector-modern/RuntimeTarget.h +6 -0
  83. package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +12 -0
  84. package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +3 -2
  85. package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
  86. package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -1
  87. package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +1 -1
  88. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
  89. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
  90. package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
  91. package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +7 -3
  92. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +52 -29
  93. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +6 -6
  94. package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
  95. package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
  96. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +12 -5
  97. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +3 -1
  98. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +42 -0
  99. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
  100. package/ReactCommon/react/debug/CMakeLists.txt +2 -1
  101. package/ReactCommon/react/debug/React-debug.podspec +7 -1
  102. package/ReactCommon/react/debug/redbox/AnsiParser.cpp +139 -0
  103. package/ReactCommon/react/debug/redbox/AnsiParser.h +35 -0
  104. package/ReactCommon/react/debug/redbox/JscSafeUrl.cpp +179 -0
  105. package/ReactCommon/react/debug/redbox/JscSafeUrl.h +27 -0
  106. package/ReactCommon/react/debug/redbox/RedBoxErrorParser.cpp +171 -0
  107. package/ReactCommon/react/debug/redbox/RedBoxErrorParser.h +40 -0
  108. package/ReactCommon/react/debug/redbox/tests/AnsiParserTest.cpp +97 -0
  109. package/ReactCommon/react/debug/redbox/tests/JscSafeUrlTest.cpp +173 -0
  110. package/ReactCommon/react/debug/redbox/tests/RedBoxErrorParserTest.cpp +107 -0
  111. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +21 -1
  112. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +26 -1
  113. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +135 -45
  114. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +12 -2
  115. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +22 -2
  116. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +46 -1
  117. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h +9 -1
  118. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +6 -1
  119. package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +3 -1
  120. package/ReactCommon/react/nativemodule/defaults/CMakeLists.txt +1 -0
  121. package/ReactCommon/react/nativemodule/defaults/DefaultTurboModules.cpp +7 -0
  122. package/ReactCommon/react/nativemodule/defaults/React-defaultsnativemodule.podspec +1 -0
  123. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +26 -1
  124. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +11 -1
  125. package/ReactCommon/react/nativemodule/mutationobserver/NativeMutationObserver.h +4 -0
  126. package/ReactCommon/react/nativemodule/mutationobserver/React-mutationobservernativemodule.podspec +66 -0
  127. package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
  128. package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
  129. package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +4 -1
  130. package/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +58 -25
  131. package/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +9 -0
  132. package/ReactCommon/react/renderer/animationbackend/AnimationChoreographer.h +5 -0
  133. package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp +10 -0
  134. package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.h +1 -0
  135. package/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h +1 -0
  136. package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
  137. package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
  138. package/package.json +11 -11
  139. package/scripts/cocoapods/utils.rb +1 -0
  140. package/scripts/codegen/generate-artifacts-executor/generateAppDependencyProvider.js +4 -4
  141. package/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js +3 -3
  142. package/scripts/codegen/generate-artifacts-executor/generateNativeCode.js +2 -3
  143. package/scripts/codegen/generate-artifacts-executor/generatePackageSwift.js +2 -2
  144. package/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js +3 -2
  145. package/scripts/codegen/generate-artifacts-executor/generateRCTThirdPartyComponents.js +3 -2
  146. package/scripts/codegen/generate-artifacts-executor/generateReactCodegenPodspec.js +2 -2
  147. package/scripts/codegen/generate-artifacts-executor/generateUnstableModulesRequiringMainQueueSetupProvider.js +3 -3
  148. package/scripts/codegen/generate-artifacts-executor/utils.js +48 -0
  149. package/scripts/react_native_pods.rb +1 -0
  150. package/scripts/replace-rncore-version.js +72 -15
  151. package/src/private/featureflags/ReactNativeFeatureFlags.js +27 -2
  152. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +6 -1
  153. package/src/private/setup/setUpDefaultReactNativeEnvironment.js +6 -0
  154. package/types/public/ReactNativeTVTypes.d.ts +8 -0
@@ -434,6 +434,9 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
434
434
 
435
435
  scrollView.snapToStart = newScrollViewProps.snapToStart;
436
436
  scrollView.snapToEnd = newScrollViewProps.snapToEnd;
437
+ #if TARGET_OS_TV
438
+ scrollView.scrollAnimationEnabled = newScrollViewProps.scrollAnimationEnabled;
439
+ #endif
437
440
 
438
441
  if (oldScrollViewProps.snapToOffsets != newScrollViewProps.snapToOffsets) {
439
442
  NSMutableArray<NSNumber *> *snapToOffsets = [NSMutableArray array];
@@ -1252,7 +1255,7 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
1252
1255
  ? CGPointMake(targetOffset, scrollView.contentOffset.y)
1253
1256
  : CGPointMake(scrollView.contentOffset.x, targetOffset);
1254
1257
  self.preferredContentOffset = targetContentOffset;
1255
- [_scrollView setContentOffset:targetContentOffset animated:YES];
1258
+ [_scrollView setContentOffset:targetContentOffset animated:scrollProps.scrollAnimationEnabled];
1256
1259
  }
1257
1260
 
1258
1261
  - (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context
@@ -1261,7 +1264,18 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
1261
1264
  self.preferredContentOffset = NO_PREFERRED_CONTENT_OFFSET;
1262
1265
  const auto &scrollProps = static_cast<const ScrollViewProps &>(*_props);
1263
1266
  BOOL hasItemSnapAlignment = scrollProps.snapToAlignment == ScrollViewSnapToAlignment::Item;
1264
- if (context.previouslyFocusedView == context.nextFocusedView || (!_props->isTVSelectable && !hasItemSnapAlignment)) {
1267
+ if (context.previouslyFocusedView == context.nextFocusedView) {
1268
+ return;
1269
+ }
1270
+ if (!_props->isTVSelectable && !hasItemSnapAlignment) {
1271
+ if (!scrollProps.scrollAnimationEnabled && [context.nextFocusedView isDescendantOfView:_scrollView]) {
1272
+ // When animations are disabled and there's no snap alignment, manually scroll
1273
+ // the focused view into view instantly. We can't let UIScrollView's default
1274
+ // focus handling do this because it uses deceleration (timer-based) that can't
1275
+ // be blocked by the animation-blocking layer.
1276
+ CGRect targetRect = [context.nextFocusedView convertRect:context.nextFocusedView.bounds toView:_scrollView];
1277
+ [_scrollView scrollRectToVisible:targetRect animated:NO];
1278
+ }
1265
1279
  return;
1266
1280
  }
1267
1281
  if (_props->isTVSelectable && context.nextFocusedView == self) {
@@ -1429,10 +1443,16 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
1429
1443
  limitedOffset = MAX(limitedOffset, 0.0);
1430
1444
  limitedOffset = MIN(limitedOffset, maxOffset);
1431
1445
 
1432
- [UIView animateWithDuration:[self swipeDuration] animations:^{
1446
+ const auto &scrollProps = static_cast<const ScrollViewProps &>(*self->_props);
1447
+ if (scrollProps.scrollAnimationEnabled) {
1448
+ [UIView animateWithDuration:[self swipeDuration] animations:^{
1449
+ self.scrollView.contentOffset =
1450
+ CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
1451
+ }];
1452
+ } else {
1433
1453
  self.scrollView.contentOffset =
1434
1454
  CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
1435
- }];
1455
+ }
1436
1456
  });
1437
1457
  }
1438
1458
 
@@ -1453,10 +1473,16 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
1453
1473
  limitedOffset = MAX(limitedOffset, 0.0);
1454
1474
  limitedOffset = MIN(limitedOffset, maxOffset);
1455
1475
 
1456
- [UIView animateWithDuration:[self swipeDuration] animations:^{
1476
+ const auto &scrollProps = static_cast<const ScrollViewProps &>(*self->_props);
1477
+ if (scrollProps.scrollAnimationEnabled) {
1478
+ [UIView animateWithDuration:[self swipeDuration] animations:^{
1479
+ self.scrollView.contentOffset =
1480
+ CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
1481
+ }];
1482
+ } else {
1457
1483
  self.scrollView.contentOffset =
1458
1484
  CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
1459
- }];
1485
+ }
1460
1486
  });
1461
1487
  }
1462
1488
 
@@ -106,6 +106,7 @@ RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock)
106
106
  RCT_EXPORT_VIEW_PROPERTY(inverted, BOOL)
107
107
  #if TARGET_OS_TV
108
108
  RCT_EXPORT_VIEW_PROPERTY(showsScrollIndex, BOOL)
109
+ RCT_EXPORT_VIEW_PROPERTY(scrollAnimationEnabled, BOOL)
109
110
  #endif
110
111
  RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustsScrollIndicatorInsets, BOOL)
111
112
  RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
@@ -102,6 +102,8 @@ val preparePrefab by
102
102
  Pair("../ReactCommon/hermes/inspector-modern/", "hermes/inspector-modern/"),
103
103
  // fabricjni
104
104
  Pair("src/main/jni/react/fabric", "react/fabric/"),
105
+ // uimanagerjni
106
+ Pair("src/main/jni/react/uimanager", "react/uimanager/"),
105
107
  // glog
106
108
  Pair(File(buildDir, "third-party-ndk/glog/exported/").absolutePath, ""),
107
109
  // jsiinpsector
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.85.0-0rc5
1
+ VERSION_NAME=0.85.3-0
2
2
  react.internal.publishingGroup=io.github.react-native-tvos
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -441,6 +441,17 @@ android {
441
441
  }
442
442
 
443
443
  prefab { create("hermesvm") { headers = prefabHeadersDir.absolutePath } }
444
+
445
+ // Mirror ReactAndroid's multi-variant publishing setup so consumers can
446
+ // pick a debug / debugOptimized / release variant of the hermes-engine
447
+ // AAR. Required by `apply(from = "../publish.gradle")` below, which uses
448
+ // `from components.default` and therefore needs a multi-variant component.
449
+ publishing {
450
+ multipleVariants {
451
+ withSourcesJar()
452
+ allVariants()
453
+ }
454
+ }
444
455
  }
445
456
 
446
457
  afterEvaluate {
@@ -460,3 +471,9 @@ tasks.withType<JavaCompile>().configureEach {
460
471
  options.compilerArgs.add("-Xlint:deprecation,unchecked")
461
472
  options.compilerArgs.add("-Werror")
462
473
  }
474
+
475
+ /* Publishing Configuration */
476
+ // Reuses the publish.gradle template applied to ReactAndroid; the file is
477
+ // generated by the build-android-artifacts EAS workflow. Resulting artifact
478
+ // coordinate: io.github.react-native-tvos:hermes-engine:<version>.
479
+ apply(from = "../publish.gradle")
@@ -3,25 +3,17 @@
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
- *
7
- * This file is modified from the original Meta source to work in the
8
- * `react-native-ci` project.
9
6
  */
10
- /* groovylint-disable CompileStatic, DuplicateStringLiteral, LineLength, NestedBlockDepth, NoDef, UnusedVariable, VariableTypeRequired */
11
7
 
12
8
  apply plugin: 'maven-publish'
13
9
  apply plugin: 'signing'
14
10
 
15
- def isSnapshot = false
16
- // Rewritten when copying this to ReactAndroid/publish.gradle
17
- def signingKey = findProperty('SIGNING_KEY')
18
- def signingPwd = findProperty('SIGNING_PWD')
19
- def sonatypeUsername = findProperty('SONATYPE_USERNAME')
20
- def sonatypePassword = findProperty('SONATYPE_PASSWORD')
11
+ def isSnapshot = findProperty("isSnapshot")?.toBoolean()
12
+ def signingKey = findProperty("SIGNING_KEY")
13
+ def signingPwd = findProperty("SIGNING_PWD")
21
14
 
22
15
  def reactAndroidProjectDir = project(':packages:react-native:ReactAndroid').projectDir
23
- def mavenTempLocalUrl = 'file:///home/expo/workingdir/build/maven-local'
24
- // Rewritten when copying this to ReactAndroid/publish.gradle
16
+ def mavenTempLocalUrl = "file:///tmp/maven-local"
25
17
 
26
18
  publishing {
27
19
  publications {
@@ -29,7 +21,7 @@ publishing {
29
21
  afterEvaluate {
30
22
  // We do a multi variant release, so for Android libraries
31
23
  // we publish `components.release`
32
- if (plugins.hasPlugin('com.android.library')) {
24
+ if (plugins.hasPlugin("com.android.library")) {
33
25
  from components.default
34
26
  }
35
27
  }
@@ -37,35 +29,35 @@ publishing {
37
29
  // We populate the publishing version using the project version,
38
30
  // appending -SNAPSHOT if on nightly or prerelase.
39
31
  if (isSnapshot) {
40
- version = this.version + '-SNAPSHOT'
32
+ version = this.version + "-SNAPSHOT"
41
33
  } else {
42
34
  version = this.version
43
35
  }
44
36
 
45
37
  pom {
46
- name = 'react-native'
47
- description = 'A framework for building native apps with React'
48
- url = 'https://github.com/facebook/react-native'
38
+ name = "react-native"
39
+ description = "A framework for building native apps with React"
40
+ url = "https://github.com/facebook/react-native"
49
41
 
50
42
  developers {
51
43
  developer {
52
- id = 'facebook'
53
- name = 'Facebook'
44
+ id = "facebook"
45
+ name = "Facebook"
54
46
  }
55
47
  }
56
48
 
57
49
  licenses {
58
50
  license {
59
- name = 'MIT License'
60
- url = 'https://github.com/facebook/react-native/blob/HEAD/LICENSE'
61
- distribution = 'repo'
51
+ name = "MIT License"
52
+ url = "https://github.com/facebook/react-native/blob/HEAD/LICENSE"
53
+ distribution = "repo"
62
54
  }
63
55
  }
64
56
 
65
57
  scm {
66
- url = 'https://github.com/facebook/react-native.git'
67
- connection = 'scm:git:https://github.com/facebook/react-native.git'
68
- developerConnection = 'scm:git:git@github.com:facebook/react-native.git'
58
+ url = "https://github.com/facebook/react-native.git"
59
+ connection = "scm:git:https://github.com/facebook/react-native.git"
60
+ developerConnection = "scm:git:git@github.com:facebook/react-native.git"
69
61
  }
70
62
  }
71
63
  }
@@ -73,36 +65,18 @@ publishing {
73
65
 
74
66
  repositories {
75
67
  maven {
76
- name = 'mavenTempLocal'
68
+ name = "mavenTempLocal"
77
69
  url = mavenTempLocalUrl
78
70
  }
79
- maven {
80
- name = 'sonatypeRelease'
81
- url = 'https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/'
82
- // url = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
83
- credentials(PasswordCredentials) {
84
- username = sonatypeUsername
85
- password = sonatypePassword
86
- }
87
- }
88
- maven {
89
- name = 'sonatypeSnapshot'
90
- url = 'https://central.sonatype.com/repository/maven-snapshots/'
91
- // url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
92
- credentials(PasswordCredentials) {
93
- username = sonatypeUsername
94
- password = sonatypePassword
95
- }
96
- }
97
71
  }
98
72
 
99
73
  if (signingKey && signingPwd) {
100
- logger.info('PGP Key found - Signing enabled')
74
+ logger.info("PGP Key found - Signing enabled")
101
75
  signing {
102
76
  useInMemoryPgpKeys(signingKey, signingPwd)
103
77
  sign(publishing.publications.release)
104
78
  }
105
79
  } else {
106
- logger.info('Signing disabled as the PGP key was not found')
80
+ logger.info("Signing disabled as the PGP key was not found")
107
81
  }
108
82
  }
@@ -17,7 +17,11 @@ internal object InspectorFlags {
17
17
  SoLoader.loadLibrary("react_devsupportjni")
18
18
  }
19
19
 
20
+ @DoNotStrip @JvmStatic external fun getScreenshotCaptureEnabled(): Boolean
21
+
20
22
  @DoNotStrip @JvmStatic external fun getFuseboxEnabled(): Boolean
21
23
 
22
24
  @DoNotStrip @JvmStatic external fun getIsProfilingBuild(): Boolean
25
+
26
+ @DoNotStrip @JvmStatic external fun getFrameRecordingEnabled(): Boolean
23
27
  }
@@ -12,5 +12,5 @@ internal data class FrameTimingSequence(
12
12
  val threadId: Int,
13
13
  val beginTimestamp: Long,
14
14
  val endTimestamp: Long,
15
- val screenshot: String? = null,
15
+ val screenshot: ByteArray? = null,
16
16
  )
@@ -12,14 +12,18 @@ import android.os.Build
12
12
  import android.os.Handler
13
13
  import android.os.Looper
14
14
  import android.os.Process
15
- import android.util.Base64
16
15
  import android.view.FrameMetrics
17
16
  import android.view.PixelCopy
18
17
  import android.view.Window
19
18
  import com.facebook.proguard.annotations.DoNotStripAny
20
19
  import java.io.ByteArrayOutputStream
20
+ import java.util.concurrent.Executors
21
+ import java.util.concurrent.atomic.AtomicBoolean
22
+ import java.util.concurrent.atomic.AtomicReference
23
+ import kotlinx.coroutines.CoroutineDispatcher
21
24
  import kotlinx.coroutines.CoroutineScope
22
25
  import kotlinx.coroutines.Dispatchers
26
+ import kotlinx.coroutines.asCoroutineDispatcher
23
27
  import kotlinx.coroutines.launch
24
28
 
25
29
  @DoNotStripAny
@@ -30,20 +34,39 @@ internal class FrameTimingsObserver(
30
34
  private val isSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
31
35
  private val mainHandler = Handler(Looper.getMainLooper())
32
36
 
37
+ // Serial dispatcher for encoding work (single background thread). We limit to 1 thread to
38
+ // minimize the performance impact of screenshot recording.
39
+ private val encodingDispatcher: CoroutineDispatcher =
40
+ Executors.newSingleThreadExecutor().asCoroutineDispatcher()
41
+
42
+ // Stores the most recently captured frame to opportunistically encode after the current frame.
43
+ // Replaced frames are emitted as timings without screenshots.
44
+ private val lastFrameBuffer = AtomicReference<FrameData?>(null)
45
+
33
46
  private var frameCounter: Int = 0
47
+ private val encodingInProgress = AtomicBoolean(false)
34
48
  @Volatile private var isTracing: Boolean = false
35
49
  @Volatile private var currentWindow: Window? = null
36
50
 
51
+ private data class FrameData(
52
+ val bitmap: Bitmap,
53
+ val frameId: Int,
54
+ val threadId: Int,
55
+ val beginTimestamp: Long,
56
+ val endTimestamp: Long,
57
+ )
58
+
37
59
  fun start() {
38
60
  if (!isSupported) {
39
61
  return
40
62
  }
41
63
 
42
64
  frameCounter = 0
65
+ encodingInProgress.set(false)
66
+ lastFrameBuffer.set(null)
43
67
  isTracing = true
44
68
 
45
- // Capture initial screenshot to ensure there's always at least one frame
46
- // recorded at the start of tracing, even if no UI changes occur
69
+ // Emit initial frame event
47
70
  val timestamp = System.nanoTime()
48
71
  emitFrameTiming(timestamp, timestamp)
49
72
 
@@ -59,6 +82,7 @@ internal class FrameTimingsObserver(
59
82
 
60
83
  currentWindow?.removeOnFrameMetricsAvailableListener(frameMetricsListener)
61
84
  mainHandler.removeCallbacksAndMessages(null)
85
+ lastFrameBuffer.getAndSet(null)?.bitmap?.recycle()
62
86
  }
63
87
 
64
88
  fun setCurrentWindow(window: Window?) {
@@ -75,8 +99,7 @@ internal class FrameTimingsObserver(
75
99
 
76
100
  private val frameMetricsListener =
77
101
  Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ ->
78
- // Guard against calls arriving after stop() has ended tracing. Async work scheduled from
79
- // previous frames will still finish.
102
+ // Guard against calls after stop()
80
103
  if (!isTracing) {
81
104
  return@OnFrameMetricsAvailableListener
82
105
  }
@@ -89,34 +112,107 @@ internal class FrameTimingsObserver(
89
112
  val frameId = frameCounter++
90
113
  val threadId = Process.myTid()
91
114
 
92
- if (screenshotsEnabled) {
93
- // Initiate PixelCopy immediately on the main thread, while still in the current frame,
94
- // then process and emit asynchronously once the copy is complete.
95
- captureScreenshot { screenshot ->
96
- CoroutineScope(Dispatchers.Default).launch {
97
- onFrameTimingSequence(
98
- FrameTimingSequence(frameId, threadId, beginTimestamp, endTimestamp, screenshot)
99
- )
115
+ if (!screenshotsEnabled) {
116
+ // Screenshots disabled - emit without screenshot
117
+ emitFrameEvent(frameId, threadId, beginTimestamp, endTimestamp, null)
118
+ return
119
+ }
120
+
121
+ captureScreenshot(frameId, threadId, beginTimestamp, endTimestamp) { frameData ->
122
+ if (frameData != null) {
123
+ if (encodingInProgress.compareAndSet(false, true)) {
124
+ // Not encoding - encode this frame immediately
125
+ encodeFrame(frameData)
126
+ } else {
127
+ // Encoding thread busy - store current screenshot in buffer for tail-capture
128
+ val oldFrameData = lastFrameBuffer.getAndSet(frameData)
129
+ if (oldFrameData != null) {
130
+ // Skipped frame - emit event without screenshot
131
+ emitFrameEvent(
132
+ oldFrameData.frameId,
133
+ oldFrameData.threadId,
134
+ oldFrameData.beginTimestamp,
135
+ oldFrameData.endTimestamp,
136
+ null,
137
+ )
138
+ oldFrameData.bitmap.recycle()
139
+ }
100
140
  }
141
+ } else {
142
+ // Failed to capture (e.g. timeout) - emit without screenshot
143
+ emitFrameEvent(frameId, threadId, beginTimestamp, endTimestamp, null)
101
144
  }
102
- } else {
103
- CoroutineScope(Dispatchers.Default).launch {
104
- onFrameTimingSequence(
105
- FrameTimingSequence(frameId, threadId, beginTimestamp, endTimestamp, null)
145
+ }
146
+ }
147
+
148
+ private fun emitFrameEvent(
149
+ frameId: Int,
150
+ threadId: Int,
151
+ beginTimestamp: Long,
152
+ endTimestamp: Long,
153
+ screenshot: ByteArray?,
154
+ ) {
155
+ CoroutineScope(Dispatchers.Default).launch {
156
+ onFrameTimingSequence(
157
+ FrameTimingSequence(frameId, threadId, beginTimestamp, endTimestamp, screenshot)
158
+ )
159
+ }
160
+ }
161
+
162
+ private fun encodeFrame(frameData: FrameData) {
163
+ CoroutineScope(encodingDispatcher).launch {
164
+ try {
165
+ val screenshot = encodeScreenshot(frameData.bitmap)
166
+ emitFrameEvent(
167
+ frameData.frameId,
168
+ frameData.threadId,
169
+ frameData.beginTimestamp,
170
+ frameData.endTimestamp,
171
+ screenshot,
106
172
  )
173
+ } finally {
174
+ frameData.bitmap.recycle()
175
+ }
176
+
177
+ // Clear encoding flag early, allowing new frames to start fresh encoding sessions
178
+ encodingInProgress.set(false)
179
+
180
+ // Opportunistically encode tail frame (if present) without blocking new frames
181
+ val tailFrame = lastFrameBuffer.getAndSet(null)
182
+ if (tailFrame != null) {
183
+ try {
184
+ val screenshot = encodeScreenshot(tailFrame.bitmap)
185
+ emitFrameEvent(
186
+ tailFrame.frameId,
187
+ tailFrame.threadId,
188
+ tailFrame.beginTimestamp,
189
+ tailFrame.endTimestamp,
190
+ screenshot,
191
+ )
192
+ } finally {
193
+ tailFrame.bitmap.recycle()
194
+ }
107
195
  }
108
196
  }
109
197
  }
110
198
 
111
199
  // Must be called from the main thread so that PixelCopy captures the current frame.
112
- private fun captureScreenshot(callback: (String?) -> Unit) {
200
+ private fun captureScreenshot(
201
+ frameId: Int,
202
+ threadId: Int,
203
+ beginTimestamp: Long,
204
+ endTimestamp: Long,
205
+ callback: (FrameData?) -> Unit,
206
+ ) {
113
207
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
208
+ // PixelCopy not available
114
209
  callback(null)
115
210
  return
116
211
  }
117
212
 
118
213
  val window = currentWindow
119
214
  if (window == null) {
215
+ // No window
120
216
  callback(null)
121
217
  return
122
218
  }
@@ -131,9 +227,7 @@ internal class FrameTimingsObserver(
131
227
  bitmap,
132
228
  { copyResult ->
133
229
  if (copyResult == PixelCopy.SUCCESS) {
134
- CoroutineScope(Dispatchers.Default).launch {
135
- callback(encodeScreenshot(window, bitmap, width, height))
136
- }
230
+ callback(FrameData(bitmap, frameId, threadId, beginTimestamp, endTimestamp))
137
231
  } else {
138
232
  bitmap.recycle()
139
233
  callback(null)
@@ -143,9 +237,12 @@ internal class FrameTimingsObserver(
143
237
  )
144
238
  }
145
239
 
146
- private fun encodeScreenshot(window: Window, bitmap: Bitmap, width: Int, height: Int): String? {
240
+ private fun encodeScreenshot(bitmap: Bitmap): ByteArray? {
147
241
  var scaledBitmap: Bitmap? = null
148
242
  return try {
243
+ val window = currentWindow ?: return null
244
+ val width = bitmap.width
245
+ val height = bitmap.height
149
246
  val density = window.context.resources.displayMetrics.density
150
247
  val scaledWidth = (width / density * SCREENSHOT_SCALE_FACTOR).toInt()
151
248
  val scaledHeight = (height / density * SCREENSHOT_SCALE_FACTOR).toInt()
@@ -155,20 +252,24 @@ internal class FrameTimingsObserver(
155
252
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Bitmap.CompressFormat.WEBP_LOSSY
156
253
  else Bitmap.CompressFormat.JPEG
157
254
 
158
- ByteArrayOutputStream().use { outputStream ->
255
+ ByteArrayOutputStream(SCREENSHOT_OUTPUT_SIZE_HINT).use { outputStream ->
159
256
  scaledBitmap.compress(compressFormat, SCREENSHOT_QUALITY, outputStream)
160
- Base64.encodeToString(outputStream.toByteArray(), Base64.NO_WRAP)
257
+ outputStream.toByteArray()
161
258
  }
162
259
  } catch (e: Exception) {
163
260
  null
164
261
  } finally {
165
262
  scaledBitmap?.recycle()
166
- bitmap.recycle()
167
263
  }
168
264
  }
169
265
 
170
266
  companion object {
171
- private const val SCREENSHOT_SCALE_FACTOR = 0.75f
267
+ private const val SCREENSHOT_SCALE_FACTOR = 1.0f
172
268
  private const val SCREENSHOT_QUALITY = 80
269
+
270
+ // Capacity hint for the ByteArrayOutputStream used during bitmap
271
+ // compression. Sized slightly above typical compressed output to minimise
272
+ // internal buffer resizing.
273
+ private const val SCREENSHOT_OUTPUT_SIZE_HINT = 65536 // 64 KB
173
274
  }
174
275
  }
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<156d4f5f35037184b6fc61ff1d856028>>
7
+ * @generated SignedSource<<dcedc4c1eba9ea605d96850aebecaf06>>
8
8
  */
9
9
 
10
10
  /**
@@ -276,6 +276,12 @@ public object ReactNativeFeatureFlags {
276
276
  @JvmStatic
277
277
  public fun enableModuleArgumentNSNullConversionIOS(): Boolean = accessor.enableModuleArgumentNSNullConversionIOS()
278
278
 
279
+ /**
280
+ * Enables the MutationObserver Web API in React Native.
281
+ */
282
+ @JvmStatic
283
+ public fun enableMutationObserverByDefault(): Boolean = accessor.enableMutationObserverByDefault()
284
+
279
285
  /**
280
286
  * Parse CSS strings using the Fabric CSS parser instead of ViewConfig processing
281
287
  */
@@ -384,12 +390,24 @@ public object ReactNativeFeatureFlags {
384
390
  @JvmStatic
385
391
  public fun fuseboxEnabledRelease(): Boolean = accessor.fuseboxEnabledRelease()
386
392
 
393
+ /**
394
+ * Enable frame timings and screenshots support in the React Native DevTools CDP backend. This flag is global and should not be changed across React Host lifetimes.
395
+ */
396
+ @JvmStatic
397
+ public fun fuseboxFrameRecordingEnabled(): Boolean = accessor.fuseboxFrameRecordingEnabled()
398
+
387
399
  /**
388
400
  * Enable network inspection support in the React Native DevTools CDP backend. Requires `enableBridgelessArchitecture`. This flag is global and should not be changed across React Host lifetimes.
389
401
  */
390
402
  @JvmStatic
391
403
  public fun fuseboxNetworkInspectionEnabled(): Boolean = accessor.fuseboxNetworkInspectionEnabled()
392
404
 
405
+ /**
406
+ * Enable Page.captureScreenshot CDP method support in the React Native DevTools CDP backend. This flag is global and should not be changed across React Host lifetimes.
407
+ */
408
+ @JvmStatic
409
+ public fun fuseboxScreenshotCaptureEnabled(): Boolean = accessor.fuseboxScreenshotCaptureEnabled()
410
+
393
411
  /**
394
412
  * Hides offscreen VirtualViews on iOS by setting hidden = YES to avoid extra cost of views
395
413
  */
@@ -426,6 +444,18 @@ public object ReactNativeFeatureFlags {
426
444
  @JvmStatic
427
445
  public fun preventShadowTreeCommitExhaustion(): Boolean = accessor.preventShadowTreeCommitExhaustion()
428
446
 
447
+ /**
448
+ * Use the redesigned RedBox error overlay on Android, styled to match the LogBox visual language.
449
+ */
450
+ @JvmStatic
451
+ public fun redBoxV2Android(): Boolean = accessor.redBoxV2Android()
452
+
453
+ /**
454
+ * Use the redesigned RedBox error overlay on iOS, styled to match the LogBox visual language.
455
+ */
456
+ @JvmStatic
457
+ public fun redBoxV2IOS(): Boolean = accessor.redBoxV2IOS()
458
+
429
459
  /**
430
460
  * Function used to enable / disable Pressibility from using W3C Pointer Events for its hover callbacks
431
461
  */