react-native 0.74.2 → 0.74.3

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 (36) hide show
  1. package/Libraries/AppDelegate/RCTAppDelegate.mm +4 -1
  2. package/Libraries/AppDelegate/RCTRootViewFactory.h +8 -0
  3. package/Libraries/AppDelegate/RCTRootViewFactory.mm +11 -3
  4. package/Libraries/Core/ReactNativeVersion.js +1 -1
  5. package/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +6 -0
  6. package/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +1 -0
  7. package/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +5 -0
  8. package/React/Base/RCTVersion.m +1 -1
  9. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +6 -1
  10. package/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +4 -0
  11. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +3 -2
  12. package/ReactAndroid/gradle.properties +1 -1
  13. package/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +2 -4
  14. package/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.java +5 -2
  15. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java +3 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.java +5 -0
  18. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  19. package/ReactCommon/jsc/JSCRuntime.cpp +30 -2
  20. package/ReactCommon/jsi/jsi/decorator.h +7 -0
  21. package/ReactCommon/jsi/jsi/jsi.h +7 -0
  22. package/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +53 -10
  23. package/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp +0 -1
  24. package/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.cpp +3 -3
  25. package/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp +28 -28
  26. package/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.h +3 -3
  27. package/ReactCommon/react/renderer/runtimescheduler/Task.cpp +9 -7
  28. package/ReactCommon/react/renderer/runtimescheduler/tests/RuntimeSchedulerTest.cpp +46 -0
  29. package/package.json +11 -11
  30. package/scripts/codegen/generate-artifacts-executor.js +1 -1
  31. package/sdks/.hermesversion +1 -1
  32. package/sdks/hermesc/osx-bin/hermes +0 -0
  33. package/sdks/hermesc/osx-bin/hermesc +0 -0
  34. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  35. package/template/package.json +5 -5
  36. package/ReactCommon/react/renderer/runtimescheduler/ErrorUtils.h +0 -34
@@ -65,7 +65,6 @@
65
65
  [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self;
66
66
  }
67
67
  [self _logWarnIfCreateRootViewWithBridgeIsOverridden];
68
- [self customizeRootView:(RCTRootView *)rootView];
69
68
 
70
69
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
71
70
  UIViewController *rootViewController = [self createRootViewController];
@@ -261,6 +260,10 @@
261
260
  return [weakSelf createBridgeWithDelegate:delegate launchOptions:launchOptions];
262
261
  };
263
262
 
263
+ configuration.customizeRootView = ^(UIView *_Nonnull rootView) {
264
+ [weakSelf customizeRootView:(RCTRootView *)rootView];
265
+ };
266
+
264
267
  return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self];
265
268
  }
266
269
 
@@ -23,6 +23,7 @@ typedef UIView *_Nonnull (
23
23
  ^RCTCreateRootViewWithBridgeBlock)(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps);
24
24
  typedef RCTBridge *_Nonnull (
25
25
  ^RCTCreateBridgeWithDelegateBlock)(id<RCTBridgeDelegate> delegate, NSDictionary *launchOptions);
26
+ typedef void (^RCTCustomizeRootViewBlock)(UIView *rootView);
26
27
  typedef NSURL *_Nullable (^RCTSourceURLForBridgeBlock)(RCTBridge *bridge);
27
28
  typedef NSURL *_Nullable (^RCTBundleURLBlock)(void);
28
29
  typedef NSArray<id<RCTBridgeModule>> *_Nonnull (^RCTExtraModulesForBridgeBlock)(RCTBridge *bridge);
@@ -91,6 +92,13 @@ typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *modu
91
92
  */
92
93
  @property (nonatomic, nullable) RCTCreateBridgeWithDelegateBlock createBridgeWithDelegate;
93
94
 
95
+ /**
96
+ * Block that allows to customize the rootView that is passed to React Native.
97
+ *
98
+ * @parameter: rootView - The root view to customize.
99
+ */
100
+ @property (nonatomic, nullable) RCTCustomizeRootViewBlock customizeRootView;
101
+
94
102
  @end
95
103
 
96
104
  #pragma mark - RCTRootViewFactory
@@ -145,17 +145,25 @@ static NSDictionary *updateInitialProps(NSDictionary *initialProps, BOOL isFabri
145
145
  initWithSurface:surface
146
146
  sizeMeasureMode:RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact];
147
147
 
148
+ if (self->_configuration.customizeRootView != nil) {
149
+ self->_configuration.customizeRootView(surfaceHostingProxyRootView);
150
+ }
148
151
  return surfaceHostingProxyRootView;
149
152
  }
150
153
 
151
154
  [self createBridgeIfNeeded:launchOptions];
152
155
  [self createBridgeAdapterIfNeeded];
153
156
 
157
+ UIView *rootView;
154
158
  if (self->_configuration.createRootViewWithBridge != nil) {
155
- return self->_configuration.createRootViewWithBridge(self.bridge, moduleName, initProps);
159
+ rootView = self->_configuration.createRootViewWithBridge(self.bridge, moduleName, initProps);
160
+ } else {
161
+ rootView = [self createRootViewWithBridge:self.bridge moduleName:moduleName initProps:initProps];
156
162
  }
157
-
158
- return [self createRootViewWithBridge:self.bridge moduleName:moduleName initProps:initProps];
163
+ if (self->_configuration.customizeRootView != nil) {
164
+ self->_configuration.customizeRootView(rootView);
165
+ }
166
+ return rootView;
159
167
  }
160
168
 
161
169
  - (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
@@ -16,7 +16,7 @@ const version: $ReadOnly<{
16
16
  }> = {
17
17
  major: 0,
18
18
  minor: 74,
19
- patch: 2,
19
+ patch: 3,
20
20
  prerelease: null,
21
21
  };
22
22
 
@@ -163,6 +163,12 @@ static UIColor *defaultPlaceholderColor(void)
163
163
  [super setSelectedTextRange:selectedTextRange];
164
164
  }
165
165
 
166
+ // After restoring the previous cursor position, we manually trigger the scroll to the new cursor position (PR 38679).
167
+ - (void)scrollRangeToVisible:(NSRange)range
168
+ {
169
+ [super scrollRangeToVisible:range];
170
+ }
171
+
166
172
  - (void)paste:(id)sender
167
173
  {
168
174
  _textWasPasted = YES;
@@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
43
43
  // If the change was a result of user actions (like typing or touches), we MUST notify the delegate.
44
44
  - (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange NS_UNAVAILABLE;
45
45
  - (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate;
46
+ - (void)scrollRangeToVisible:(NSRange)selectedTextRange;
46
47
 
47
48
  // This protocol disallows direct access to `text` property because
48
49
  // unwise usage of it can break the `attributeText` behavior.
@@ -201,6 +201,11 @@
201
201
  [super setSelectedTextRange:selectedTextRange];
202
202
  }
203
203
 
204
+ - (void)scrollRangeToVisible:(NSRange)range
205
+ {
206
+ // Singleline TextInput does not require scrolling after calling setSelectedTextRange (PR 38679).
207
+ }
208
+
204
209
  - (void)paste:(id)sender
205
210
  {
206
211
  _textWasPasted = YES;
@@ -23,7 +23,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(74),
26
- RCTVersionPatch: @(2),
26
+ RCTVersionPatch: @(3),
27
27
  RCTVersionPrerelease: [NSNull null],
28
28
  };
29
29
  });
@@ -122,8 +122,8 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
122
122
  {
123
123
  if (self = [super initWithFrame:frame]) {
124
124
  _props = ScrollViewShadowNode::defaultSharedProps();
125
-
126
125
  _scrollView = [[RCTEnhancedScrollView alloc] initWithFrame:self.bounds];
126
+ _scrollView.clipsToBounds = _props->getClipsContentToBounds();
127
127
  _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
128
128
  _scrollView.delaysContentTouches = NO;
129
129
  ((RCTEnhancedScrollView *)_scrollView).overridingDelegate = self;
@@ -253,6 +253,11 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
253
253
  }
254
254
  }
255
255
 
256
+ // Overflow prop
257
+ if (oldScrollViewProps.getClipsContentToBounds() != newScrollViewProps.getClipsContentToBounds()) {
258
+ _scrollView.clipsToBounds = newScrollViewProps.getClipsContentToBounds();
259
+ }
260
+
256
261
  MAP_SCROLL_VIEW_PROP(zoomScale);
257
262
 
258
263
  if (oldScrollViewProps.contentInset != newScrollViewProps.contentInset) {
@@ -594,6 +594,9 @@ using namespace facebook::react;
594
594
  UITextRange *selectedRange = _backedTextInputView.selectedTextRange;
595
595
  NSInteger oldTextLength = _backedTextInputView.attributedText.string.length;
596
596
  _backedTextInputView.attributedText = attributedString;
597
+ // Updating the UITextView attributedText, for example changing the lineHeight, the color or adding
598
+ // a new paragraph with \n, causes the cursor to move to the end of the Text and scroll.
599
+ // This is fixed by restoring the cursor position and scrolling to that position (iOS issue 652653).
597
600
  if (selectedRange.empty) {
598
601
  // Maintaining a cursor position relative to the end of the old text.
599
602
  NSInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
@@ -604,6 +607,7 @@ using namespace facebook::react;
604
607
  offset:newOffset];
605
608
  [_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
606
609
  notifyDelegate:YES];
610
+ [_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
607
611
  }
608
612
  [self _restoreTextSelection];
609
613
  _lastStringStateWasUpdatedWith = attributedString;
@@ -633,8 +633,9 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
633
633
  // iOS draws borders in front of the content whereas CSS draws them behind
634
634
  // the content. For this reason, only use iOS border drawing when clipping
635
635
  // or when the border is hidden.
636
- borderMetrics.borderWidths.left == 0 ||
637
- colorComponentsFromColor(borderMetrics.borderColors.left).alpha == 0 || self.clipsToBounds);
636
+ borderMetrics.borderWidths.left == 0 || self.clipsToBounds ||
637
+ (colorComponentsFromColor(borderMetrics.borderColors.left).alpha == 0 &&
638
+ (*borderMetrics.borderColors.left).getUIColor() != nullptr));
638
639
 
639
640
  CGColorRef backgroundColor = [_backgroundColor resolvedColorWithTraitCollection:self.traitCollection].CGColor;
640
641
 
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.74.2
1
+ VERSION_NAME=0.74.3
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
 
4
4
  android.useAndroidX=true
@@ -432,10 +432,8 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
432
432
 
433
433
  if (mShouldLogContentAppeared) {
434
434
  mShouldLogContentAppeared = false;
435
-
436
- if (mJSModuleName != null) {
437
- ReactMarker.logMarker(ReactMarkerConstants.CONTENT_APPEARED, mJSModuleName, mRootViewTag);
438
- }
435
+ String jsModuleName = getJSModuleName();
436
+ ReactMarker.logMarker(ReactMarkerConstants.CONTENT_APPEARED, jsModuleName, mRootViewTag);
439
437
  }
440
438
  }
441
439
 
@@ -99,8 +99,11 @@ public class JavaTimerManager {
99
99
  }
100
100
 
101
101
  // If the JS thread is busy for multiple frames we cancel any other pending runnable.
102
- if (mCurrentIdleCallbackRunnable != null) {
103
- mCurrentIdleCallbackRunnable.cancel();
102
+ // We also capture the idleCallbackRunnable to tentatively fix:
103
+ // https://github.com/facebook/react-native/issues/44842
104
+ IdleCallbackRunnable idleCallbackRunnable = mCurrentIdleCallbackRunnable;
105
+ if (idleCallbackRunnable != null) {
106
+ idleCallbackRunnable.cancel();
104
107
  }
105
108
 
106
109
  mCurrentIdleCallbackRunnable = new IdleCallbackRunnable(frameTimeNanos);
@@ -17,6 +17,6 @@ public class ReactNativeVersion {
17
17
  public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
18
18
  "major", 0,
19
19
  "minor", 74,
20
- "patch", 2,
20
+ "patch", 3,
21
21
  "prerelease", null);
22
22
  }
@@ -378,7 +378,9 @@ public class ReactHostImpl implements ReactHost {
378
378
  public ReactSurface createSurface(
379
379
  Context context, String moduleName, @Nullable Bundle initialProps) {
380
380
  ReactSurfaceImpl surface = new ReactSurfaceImpl(context, moduleName, initialProps);
381
- surface.attachView(new ReactSurfaceView(context, surface));
381
+ ReactSurfaceView surfaceView = new ReactSurfaceView(context, surface);
382
+ surfaceView.setShouldLogContentAppeared(true);
383
+ surface.attachView(surfaceView);
382
384
  surface.attach(this);
383
385
  return surface;
384
386
  }
@@ -189,6 +189,11 @@ public class ReactSurfaceView extends ReactRootView {
189
189
  return UIManagerType.FABRIC;
190
190
  }
191
191
 
192
+ @Override
193
+ public String getJSModuleName() {
194
+ return mSurface.getModuleName();
195
+ }
196
+
192
197
  @Override
193
198
  protected void dispatchJSTouchEvent(MotionEvent event) {
194
199
  if (mJSTouchDispatcher == null) {
@@ -17,7 +17,7 @@ namespace facebook::react {
17
17
  constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 74;
20
- int32_t Patch = 2;
20
+ int32_t Patch = 3;
21
21
  std::string_view Prerelease = "";
22
22
  } ReactNativeVersion;
23
23
 
@@ -13,8 +13,8 @@
13
13
  #include <atomic>
14
14
  #include <condition_variable>
15
15
  #include <cstdlib>
16
+ #include <deque>
16
17
  #include <mutex>
17
- #include <queue>
18
18
  #include <sstream>
19
19
  #include <thread>
20
20
 
@@ -51,6 +51,12 @@ class JSCRuntime : public jsi::Runtime {
51
51
  const std::shared_ptr<const jsi::Buffer>& buffer,
52
52
  const std::string& sourceURL) override;
53
53
 
54
+ // If we use this interface to implement microtasks in the host we need to
55
+ // polyfill `Promise` to use these methods, because JSC doesn't currently
56
+ // support providing a custom queue for its built-in implementation.
57
+ // Not doing this would result in a non-compliant behavior, as microtasks
58
+ // wouldn't execute in the order in which they were queued.
59
+ void queueMicrotask(const jsi::Function& callback) override;
54
60
  bool drainMicrotasks(int maxMicrotasksHint = -1) override;
55
61
 
56
62
  jsi::Object global() override;
@@ -265,6 +271,7 @@ class JSCRuntime : public jsi::Runtime {
265
271
  std::atomic<bool> ctxInvalid_;
266
272
  std::string desc_;
267
273
  JSValueRef nativeStateSymbol_ = nullptr;
274
+ std::deque<jsi::Function> microtaskQueue_;
268
275
  #ifndef NDEBUG
269
276
  mutable std::atomic<intptr_t> objectCounter_;
270
277
  mutable std::atomic<intptr_t> symbolCounter_;
@@ -380,6 +387,10 @@ JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
380
387
  }
381
388
 
382
389
  JSCRuntime::~JSCRuntime() {
390
+ // We need to clear the microtask queue to remove all references to the
391
+ // callbacks, so objectCounter_ would be 0 below.
392
+ microtaskQueue_.clear();
393
+
383
394
  // On shutting down and cleaning up: when JSC is actually torn down,
384
395
  // it calls JSC::Heap::lastChanceToFinalize internally which
385
396
  // finalizes anything left over. But at this point,
@@ -436,7 +447,24 @@ jsi::Value JSCRuntime::evaluateJavaScript(
436
447
  return createValue(res);
437
448
  }
438
449
 
439
- bool JSCRuntime::drainMicrotasks(int maxMicrotasksHint) {
450
+ void JSCRuntime::queueMicrotask(const jsi::Function& callback) {
451
+ microtaskQueue_.emplace_back(
452
+ jsi::Value(*this, callback).asObject(*this).asFunction(*this));
453
+ }
454
+
455
+ bool JSCRuntime::drainMicrotasks(int /*maxMicrotasksHint*/) {
456
+ // Note that new jobs can be enqueued during the draining.
457
+ while (!microtaskQueue_.empty()) {
458
+ jsi::Function callback = std::move(microtaskQueue_.front());
459
+
460
+ // We need to pop before calling the callback because that might throw.
461
+ // When that happens, the host will call `drainMicrotasks` again to execute
462
+ // the remaining microtasks, and this one shouldn't run again.
463
+ microtaskQueue_.pop_front();
464
+
465
+ callback.call(*this);
466
+ }
467
+
440
468
  return true;
441
469
  }
442
470
 
@@ -126,6 +126,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
126
126
  const std::shared_ptr<const PreparedJavaScript>& js) override {
127
127
  return plain().evaluatePreparedJavaScript(js);
128
128
  }
129
+ void queueMicrotask(const jsi::Function& callback) override {
130
+ return plain().queueMicrotask(callback);
131
+ }
129
132
  bool drainMicrotasks(int maxMicrotasksHint) override {
130
133
  return plain().drainMicrotasks(maxMicrotasksHint);
131
134
  }
@@ -544,6 +547,10 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
544
547
  Around around{with_};
545
548
  return RD::evaluatePreparedJavaScript(js);
546
549
  }
550
+ void queueMicrotask(const Function& callback) override {
551
+ Around around{with_};
552
+ RD::queueMicrotask(callback);
553
+ }
547
554
  bool drainMicrotasks(int maxMicrotasksHint) override {
548
555
  Around around{with_};
549
556
  return RD::drainMicrotasks(maxMicrotasksHint);
@@ -209,6 +209,13 @@ class JSI_EXPORT Runtime {
209
209
  virtual Value evaluatePreparedJavaScript(
210
210
  const std::shared_ptr<const PreparedJavaScript>& js) = 0;
211
211
 
212
+ /// Queues a microtask in the JavaScript VM internal Microtask (a.k.a. Job in
213
+ /// ECMA262) queue, to be executed when the host drains microtasks in
214
+ /// its event loop implementation.
215
+ ///
216
+ /// \param callback a function to be executed as a microtask.
217
+ virtual void queueMicrotask(const jsi::Function& callback) = 0;
218
+
212
219
  /// Drain the JavaScript VM internal Microtask (a.k.a. Job in ECMA262) queue.
213
220
  ///
214
221
  /// \param maxMicrotasksHint a hint to tell an implementation that it should
@@ -86,6 +86,38 @@ struct JNIArgs {
86
86
  std::vector<jobject> globalRefs_;
87
87
  };
88
88
 
89
+ jsi::Value createJSRuntimeError(
90
+ jsi::Runtime& runtime,
91
+ const std::string& message) {
92
+ return runtime.global()
93
+ .getPropertyAsFunction(runtime, "Error")
94
+ .call(runtime, message);
95
+ }
96
+
97
+ jsi::Value createRejectionError(jsi::Runtime& rt, const folly::dynamic& args) {
98
+ react_native_assert(
99
+ args.size() == 1 && "promise reject should has only one argument");
100
+
101
+ auto value = jsi::valueFromDynamic(rt, args[0]);
102
+ react_native_assert(value.isObject() && "promise reject should return a map");
103
+
104
+ const jsi::Object& valueAsObject = value.asObject(rt);
105
+
106
+ auto messageProperty = valueAsObject.getProperty(rt, "message");
107
+ auto jsError =
108
+ createJSRuntimeError(rt, messageProperty.asString(rt).utf8(rt));
109
+
110
+ auto jsErrorAsObject = jsError.asObject(rt);
111
+ auto propertyNames = valueAsObject.getPropertyNames(rt);
112
+ for (size_t i = 0; i < propertyNames.size(rt); ++i) {
113
+ auto propertyName = jsi::PropNameID::forString(
114
+ rt, propertyNames.getValueAtIndex(rt, i).asString(rt));
115
+ jsErrorAsObject.setProperty(
116
+ rt, propertyName, valueAsObject.getProperty(rt, propertyName));
117
+ }
118
+ return jsError;
119
+ }
120
+
89
121
  auto createJavaCallback(
90
122
  jsi::Runtime& rt,
91
123
  jsi::Function&& function,
@@ -98,7 +130,6 @@ auto createJavaCallback(
98
130
  LOG(FATAL) << "Callback arg cannot be called more than once";
99
131
  return;
100
132
  }
101
-
102
133
  callback->call([args = std::move(args)](
103
134
  jsi::Runtime& rt, jsi::Function& jsFunction) {
104
135
  std::vector<jsi::Value> jsArgs;
@@ -112,6 +143,26 @@ auto createJavaCallback(
112
143
  });
113
144
  }
114
145
 
146
+ auto createJavaRejectCallback(
147
+ jsi::Runtime& rt,
148
+ jsi::Function&& function,
149
+ std::shared_ptr<CallInvoker> jsInvoker) {
150
+ std::optional<AsyncCallback<>> callback(
151
+ {rt, std::move(function), std::move(jsInvoker)});
152
+ return JCxxCallbackImpl::newObjectCxxArgs(
153
+ [callback = std::move(callback)](folly::dynamic args) mutable {
154
+ if (!callback) {
155
+ LOG(FATAL) << "Callback arg cannot be called more than once";
156
+ return;
157
+ }
158
+ callback->call([args = std::move(args)](
159
+ jsi::Runtime& rt, jsi::Function& jsFunction) {
160
+ jsFunction.call(rt, createRejectionError(rt, args));
161
+ });
162
+ callback = std::nullopt;
163
+ });
164
+ }
165
+
115
166
  struct JPromiseImpl : public jni::JavaClass<JPromiseImpl> {
116
167
  constexpr static auto kJavaDescriptor =
117
168
  "Lcom/facebook/react/bridge/PromiseImpl;";
@@ -407,14 +458,6 @@ jsi::Value convertFromJMapToValue(JNIEnv* env, jsi::Runtime& rt, jobject arg) {
407
458
  return jsi::valueFromDynamic(rt, result->cthis()->consume());
408
459
  }
409
460
 
410
- jsi::Value createJSRuntimeError(
411
- jsi::Runtime& runtime,
412
- const std::string& message) {
413
- return runtime.global()
414
- .getPropertyAsFunction(runtime, "Error")
415
- .call(runtime, message);
416
- }
417
-
418
461
  /**
419
462
  * Creates JSError with current JS runtime stack and Throwable stack trace.
420
463
  */
@@ -855,7 +898,7 @@ jsi::Value JavaTurboModule::invokeJavaMethod(
855
898
  runtime,
856
899
  args[0].getObject(runtime).getFunction(runtime),
857
900
  jsInvoker_);
858
- auto reject = createJavaCallback(
901
+ auto reject = createJavaRejectCallback(
859
902
  runtime,
860
903
  args[1].getObject(runtime).getFunction(runtime),
861
904
  jsInvoker_);
@@ -13,7 +13,6 @@
13
13
  #include <react/featureflags/ReactNativeFeatureFlags.h>
14
14
  #include <react/renderer/debug/SystraceSection.h>
15
15
  #include <utility>
16
- #include "ErrorUtils.h"
17
16
 
18
17
  namespace facebook::react {
19
18
 
@@ -8,9 +8,9 @@
8
8
  #include "RuntimeScheduler_Legacy.h"
9
9
  #include "SchedulerPriorityUtils.h"
10
10
 
11
+ #include <cxxreact/ErrorUtils.h>
11
12
  #include <react/renderer/debug/SystraceSection.h>
12
13
  #include <utility>
13
- #include "ErrorUtils.h"
14
14
 
15
15
  namespace facebook::react {
16
16
 
@@ -136,7 +136,7 @@ void RuntimeScheduler_Legacy::callExpiredTasks(jsi::Runtime& runtime) {
136
136
  executeTask(runtime, topPriorityTask, didUserCallbackTimeout);
137
137
  }
138
138
  } catch (jsi::JSError& error) {
139
- handleFatalError(runtime, error);
139
+ handleJSError(runtime, error, true);
140
140
  }
141
141
 
142
142
  currentPriority_ = previousPriority;
@@ -182,7 +182,7 @@ void RuntimeScheduler_Legacy::startWorkLoop(jsi::Runtime& runtime) {
182
182
  executeTask(runtime, topPriorityTask, didUserCallbackTimeout);
183
183
  }
184
184
  } catch (jsi::JSError& error) {
185
- handleFatalError(runtime, error);
185
+ handleJSError(runtime, error, true);
186
186
  }
187
187
 
188
188
  currentPriority_ = previousPriority;
@@ -12,7 +12,6 @@
12
12
  #include <react/featureflags/ReactNativeFeatureFlags.h>
13
13
  #include <react/renderer/debug/SystraceSection.h>
14
14
  #include <utility>
15
- #include "ErrorUtils.h"
16
15
 
17
16
  namespace facebook::react {
18
17
 
@@ -104,7 +103,7 @@ bool RuntimeScheduler_Modern::getShouldYield() const noexcept {
104
103
  std::shared_lock lock(schedulingMutex_);
105
104
 
106
105
  return syncTaskRequests_ > 0 ||
107
- (!taskQueue_.empty() && taskQueue_.top() != currentTask_);
106
+ (!taskQueue_.empty() && taskQueue_.top().get() != currentTask_);
108
107
  }
109
108
 
110
109
  bool RuntimeScheduler_Modern::getIsSynchronous() const noexcept {
@@ -144,9 +143,8 @@ void RuntimeScheduler_Modern::executeNowOnTheSameThread(
144
143
  auto priority = SchedulerPriority::ImmediatePriority;
145
144
  auto expirationTime =
146
145
  currentTime + timeoutForSchedulerPriority(priority);
147
- auto task = std::make_shared<Task>(
148
- priority, std::move(callback), expirationTime);
149
146
 
147
+ auto task = Task{priority, std::move(callback), expirationTime};
150
148
  executeTask(runtime, task, currentTime);
151
149
 
152
150
  isSynchronous_ = false;
@@ -231,21 +229,17 @@ void RuntimeScheduler_Modern::startWorkLoop(
231
229
 
232
230
  auto previousPriority = currentPriority_;
233
231
 
234
- try {
235
- while (syncTaskRequests_ == 0) {
236
- auto currentTime = now_();
237
- auto topPriorityTask = selectTask(currentTime, onlyExpired);
232
+ while (syncTaskRequests_ == 0) {
233
+ auto currentTime = now_();
234
+ auto topPriorityTask = selectTask(currentTime, onlyExpired);
238
235
 
239
- if (!topPriorityTask) {
240
- // No pending work to do.
241
- // Events will restart the loop when necessary.
242
- break;
243
- }
244
-
245
- executeTask(runtime, topPriorityTask, currentTime);
236
+ if (!topPriorityTask) {
237
+ // No pending work to do.
238
+ // Events will restart the loop when necessary.
239
+ break;
246
240
  }
247
- } catch (jsi::JSError& error) {
248
- handleFatalError(runtime, error);
241
+
242
+ executeTask(runtime, *topPriorityTask, currentTime);
249
243
  }
250
244
 
251
245
  currentPriority_ = previousPriority;
@@ -280,19 +274,19 @@ std::shared_ptr<Task> RuntimeScheduler_Modern::selectTask(
280
274
 
281
275
  void RuntimeScheduler_Modern::executeTask(
282
276
  jsi::Runtime& runtime,
283
- const std::shared_ptr<Task>& task,
277
+ Task& task,
284
278
  RuntimeSchedulerTimePoint currentTime) {
285
- auto didUserCallbackTimeout = task->expirationTime <= currentTime;
279
+ auto didUserCallbackTimeout = task.expirationTime <= currentTime;
286
280
 
287
281
  SystraceSection s(
288
282
  "RuntimeScheduler::executeTask",
289
283
  "priority",
290
- serialize(task->priority),
284
+ serialize(task.priority),
291
285
  "didUserCallbackTimeout",
292
286
  didUserCallbackTimeout);
293
287
 
294
- currentTask_ = task;
295
- currentPriority_ = task->priority;
288
+ currentTask_ = &task;
289
+ currentPriority_ = task.priority;
296
290
 
297
291
  executeMacrotask(runtime, task, didUserCallbackTimeout);
298
292
 
@@ -305,6 +299,8 @@ void RuntimeScheduler_Modern::executeTask(
305
299
  // "Update the rendering" step.
306
300
  updateRendering();
307
301
  }
302
+
303
+ currentTask_ = nullptr;
308
304
  }
309
305
 
310
306
  /**
@@ -326,16 +322,20 @@ void RuntimeScheduler_Modern::updateRendering() {
326
322
 
327
323
  void RuntimeScheduler_Modern::executeMacrotask(
328
324
  jsi::Runtime& runtime,
329
- std::shared_ptr<Task> task,
325
+ Task& task,
330
326
  bool didUserCallbackTimeout) const {
331
327
  SystraceSection s("RuntimeScheduler::executeMacrotask");
332
328
 
333
- auto result = task->execute(runtime, didUserCallbackTimeout);
329
+ try {
330
+ auto result = task.execute(runtime, didUserCallbackTimeout);
334
331
 
335
- if (result.isObject() && result.getObject(runtime).isFunction(runtime)) {
336
- // If the task returned a continuation callback, we re-assign it to the task
337
- // and keep the task in the queue.
338
- task->callback = result.getObject(runtime).getFunction(runtime);
332
+ if (result.isObject() && result.getObject(runtime).isFunction(runtime)) {
333
+ // If the task returned a continuation callback, we re-assign it to the
334
+ // task and keep the task in the queue.
335
+ task.callback = result.getObject(runtime).getFunction(runtime);
336
+ }
337
+ } catch (jsi::JSError& error) {
338
+ handleJSError(runtime, error, true);
339
339
  }
340
340
  }
341
341
 
@@ -139,7 +139,7 @@ class RuntimeScheduler_Modern final : public RuntimeSchedulerBase {
139
139
  TaskPriorityComparer>
140
140
  taskQueue_;
141
141
 
142
- std::shared_ptr<Task> currentTask_;
142
+ Task* currentTask_{};
143
143
 
144
144
  /**
145
145
  * This protects the access to `taskQueue_` and `isWorkLoopScheduled_`.
@@ -168,12 +168,12 @@ class RuntimeScheduler_Modern final : public RuntimeSchedulerBase {
168
168
  */
169
169
  void executeTask(
170
170
  jsi::Runtime& runtime,
171
- const std::shared_ptr<Task>& task,
171
+ Task& task,
172
172
  RuntimeSchedulerTimePoint currentTime);
173
173
 
174
174
  void executeMacrotask(
175
175
  jsi::Runtime& runtime,
176
- std::shared_ptr<Task> task,
176
+ Task& task,
177
177
  bool didUserCallbackTimeout) const;
178
178
 
179
179
  void updateRendering();
@@ -32,20 +32,22 @@ jsi::Value Task::execute(jsi::Runtime& runtime, bool didUserCallbackTimeout) {
32
32
  return result;
33
33
  }
34
34
 
35
- auto& cbVal = callback.value();
35
+ // We get the value of the callback and reset it immediately to avoid it being
36
+ // called more than once (including when the callback throws).
37
+ auto originalCallback = std::move(*callback);
38
+ callback.reset();
36
39
 
37
- if (cbVal.index() == 0) {
40
+ if (originalCallback.index() == 0) {
38
41
  // Callback in JavaScript is expecting a single bool parameter.
39
42
  // React team plans to remove it in the future when a scheduler bug on web
40
43
  // is resolved.
41
- result =
42
- std::get<jsi::Function>(cbVal).call(runtime, {didUserCallbackTimeout});
44
+ result = std::get<jsi::Function>(originalCallback)
45
+ .call(runtime, {didUserCallbackTimeout});
43
46
  } else {
44
47
  // Calling a raw callback
45
- std::get<RawCallback>(cbVal)(runtime);
48
+ std::get<RawCallback>(originalCallback)(runtime);
46
49
  }
47
- // Destroying callback to prevent calling it twice.
48
- callback.reset();
50
+
49
51
  return result;
50
52
  }
51
53
 
@@ -1021,6 +1021,52 @@ TEST_P(RuntimeSchedulerTest, modernTwoThreadsRequestAccessToTheRuntime) {
1021
1021
  EXPECT_EQ(stubQueue_->size(), 0);
1022
1022
  }
1023
1023
 
1024
+ TEST_P(RuntimeSchedulerTest, errorInTaskShouldNotStopMicrotasks) {
1025
+ // Only for modern runtime scheduler
1026
+ if (!GetParam()) {
1027
+ return;
1028
+ }
1029
+
1030
+ auto microtaskRan = false;
1031
+ auto taskRan = false;
1032
+
1033
+ auto callback = createHostFunctionFromLambda([&](bool /* unused */) {
1034
+ taskRan = true;
1035
+
1036
+ auto microtaskCallback = jsi::Function::createFromHostFunction(
1037
+ *runtime_,
1038
+ jsi::PropNameID::forUtf8(*runtime_, "microtask1"),
1039
+ 3,
1040
+ [&](jsi::Runtime& /*unused*/,
1041
+ const jsi::Value& /*unused*/,
1042
+ const jsi::Value* /*arguments*/,
1043
+ size_t /*unused*/) -> jsi::Value {
1044
+ microtaskRan = true;
1045
+ return jsi::Value::undefined();
1046
+ });
1047
+
1048
+ runtime_->queueMicrotask(microtaskCallback);
1049
+
1050
+ throw jsi::JSError(*runtime_, "Test error");
1051
+
1052
+ return jsi::Value::undefined();
1053
+ });
1054
+
1055
+ runtimeScheduler_->scheduleTask(
1056
+ SchedulerPriority::NormalPriority, std::move(callback));
1057
+
1058
+ EXPECT_EQ(taskRan, false);
1059
+ EXPECT_EQ(microtaskRan, false);
1060
+ EXPECT_EQ(stubQueue_->size(), 1);
1061
+
1062
+ stubQueue_->tick();
1063
+
1064
+ EXPECT_EQ(taskRan, 1);
1065
+ EXPECT_EQ(microtaskRan, 1);
1066
+ EXPECT_EQ(stubQueue_->size(), 0);
1067
+ EXPECT_EQ(stubErrorUtils_->getReportFatalCallCount(), 1);
1068
+ }
1069
+
1024
1070
  INSTANTIATE_TEST_SUITE_P(
1025
1071
  UseModernRuntimeScheduler,
1026
1072
  RuntimeSchedulerTest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.74.2",
3
+ "version": "0.74.3",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -107,16 +107,16 @@
107
107
  },
108
108
  "dependencies": {
109
109
  "@jest/create-cache-key-function": "^29.6.3",
110
- "@react-native-community/cli": "13.6.8",
111
- "@react-native-community/cli-platform-android": "13.6.8",
112
- "@react-native-community/cli-platform-ios": "13.6.8",
113
- "@react-native/assets-registry": "0.74.84",
114
- "@react-native/codegen": "0.74.84",
115
- "@react-native/community-cli-plugin": "0.74.84",
116
- "@react-native/gradle-plugin": "0.74.84",
117
- "@react-native/js-polyfills": "0.74.84",
118
- "@react-native/normalize-colors": "0.74.84",
119
- "@react-native/virtualized-lists": "0.74.84",
110
+ "@react-native-community/cli": "13.6.9",
111
+ "@react-native-community/cli-platform-android": "13.6.9",
112
+ "@react-native-community/cli-platform-ios": "13.6.9",
113
+ "@react-native/assets-registry": "0.74.85",
114
+ "@react-native/codegen": "0.74.85",
115
+ "@react-native/community-cli-plugin": "0.74.85",
116
+ "@react-native/gradle-plugin": "0.74.85",
117
+ "@react-native/js-polyfills": "0.74.85",
118
+ "@react-native/normalize-colors": "0.74.85",
119
+ "@react-native/virtualized-lists": "0.74.85",
120
120
  "abort-controller": "^3.0.0",
121
121
  "anser": "^1.4.9",
122
122
  "ansi-regex": "^5.0.0",
@@ -364,7 +364,7 @@ function computeOutputPath(projectRoot, baseOutputPath, pkgJson, platform) {
364
364
  if (baseOutputPath == null) {
365
365
  const outputDirFromPkgJson = readOutputDirFromPkgJson(pkgJson, platform);
366
366
  if (outputDirFromPkgJson != null) {
367
- baseOutputPath = outputDirFromPkgJson;
367
+ baseOutputPath = path.join(projectRoot, outputDirFromPkgJson);
368
368
  } else {
369
369
  baseOutputPath = projectRoot;
370
370
  }
@@ -1 +1 @@
1
- hermes-2024-06-03-RNv0.74.2-bb1e74fe1e95c2b5a2f4f9311152da052badc2bc
1
+ hermes-2024-06-28-RNv0.74.3-7bda0c267e76d11b68a585f84cfdd65000babf85
Binary file
Binary file
Binary file
@@ -11,16 +11,16 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "react": "18.2.0",
14
- "react-native": "0.74.2"
14
+ "react-native": "0.74.3"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@babel/core": "^7.20.0",
18
18
  "@babel/preset-env": "^7.20.0",
19
19
  "@babel/runtime": "^7.20.0",
20
- "@react-native/babel-preset": "0.74.84",
21
- "@react-native/eslint-config": "0.74.84",
22
- "@react-native/metro-config": "0.74.84",
23
- "@react-native/typescript-config": "0.74.84",
20
+ "@react-native/babel-preset": "0.74.85",
21
+ "@react-native/eslint-config": "0.74.85",
22
+ "@react-native/metro-config": "0.74.85",
23
+ "@react-native/typescript-config": "0.74.85",
24
24
  "@types/react": "^18.2.6",
25
25
  "@types/react-test-renderer": "^18.0.0",
26
26
  "babel-jest": "^29.6.3",
@@ -1,34 +0,0 @@
1
- /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
- #include <jsi/jsi.h>
9
-
10
- namespace facebook::react {
11
-
12
- inline static void handleFatalError(
13
- jsi::Runtime& runtime,
14
- const jsi::JSError& error) {
15
- auto reportFatalError = "reportFatalError";
16
- auto errorUtils = runtime.global().getProperty(runtime, "ErrorUtils");
17
- if (errorUtils.isUndefined() || !errorUtils.isObject() ||
18
- !errorUtils.getObject(runtime).hasProperty(runtime, reportFatalError)) {
19
- // ErrorUtils was not set up. This probably means the bundle didn't
20
- // load properly.
21
- throw jsi::JSError(
22
- runtime,
23
- "ErrorUtils is not set up properly. Something probably went wrong trying to load the JS bundle. Trying to report error " +
24
- error.getMessage(),
25
- error.getStack());
26
- }
27
-
28
- auto func = errorUtils.asObject(runtime).getPropertyAsFunction(
29
- runtime, reportFatalError);
30
-
31
- func.call(runtime, error.value());
32
- }
33
-
34
- } // namespace facebook::react