diff --git a/.flowconfig b/.flowconfig index c7aa3f075c7e0f..e6ad16c7bcc1bf 100644 --- a/.flowconfig +++ b/.flowconfig @@ -71,4 +71,4 @@ untyped-import untyped-type-import [version] -^0.158.0 +^0.159.0 diff --git a/.flowconfig.android b/.flowconfig.android index 96b27477635f11..53110b81ff775e 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -71,4 +71,4 @@ untyped-import untyped-type-import [version] -^0.158.0 +^0.159.0 diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index deebd5102e05a3..b2f092d58456ec 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -161,11 +161,6 @@ class DrawerLayoutAndroid extends React.Component { return {Left: 'left', Right: 'right'}; } - static defaultProps: {| - drawerBackgroundColor: 'white', - |} = { - drawerBackgroundColor: 'white', - }; _nativeRef = React.createRef< React.ElementRef, @@ -175,6 +170,7 @@ class DrawerLayoutAndroid extends React.Component { render(): React.Node { const { + drawerBackgroundColor = 'white', onDrawerStateChanged, renderNavigationView, onDrawerOpen, @@ -189,7 +185,7 @@ class DrawerLayoutAndroid extends React.Component { styles.drawerSubview, { width: this.props.drawerWidth, - backgroundColor: this.props.drawerBackgroundColor, + backgroundColor: drawerBackgroundColor, }, ]} collapsable={false}> @@ -220,6 +216,7 @@ class DrawerLayoutAndroid extends React.Component { should render as expected: should deep render w exports[` should render as expected: should shallow render as when mocked 1`] = ` should render as expected: should shallow rende exports[` should render as expected: should shallow render as when not mocked 1`] = ` { ); } } - if (Platform.OS === 'android') { - if (this.props.keyboardDismissMode === 'on-drag' && this._isTouching) { - dismissKeyboard(); - } - } this._observedScrollSinceBecomingResponder = true; this.props.onScroll && this.props.onScroll(e); }; @@ -1299,6 +1294,14 @@ class ScrollView extends React.Component { */ _handleScrollBeginDrag: (e: ScrollEvent) => void = (e: ScrollEvent) => { FrameRateLogger.beginScroll(); // TODO: track all scrolls after implementing onScrollEndAnimation + + if ( + Platform.OS === 'android' && + this.props.keyboardDismissMode === 'on-drag' + ) { + dismissKeyboard(); + } + this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e); }; diff --git a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index f530be611602e1..ea21ce221b757e 100644 --- a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -4,25 +4,29 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict-local + * @flow * @format */ -import type {LayoutEvent} from '../../Types/CoreEventTypes'; -import setAndForwardRef from 'react-native/Libraries/Utilities/setAndForwardRef'; -import Platform from '../../Utilities/Platform'; -import StyleSheet from '../../StyleSheet/StyleSheet'; -import Animated from '../../Animated/Animated'; +import AnimatedImplementation from '../../Animated/AnimatedImplementation'; +import AnimatedAddition from '../../Animated/nodes/AnimatedAddition'; +import AnimatedDiffClamp from '../../Animated/nodes/AnimatedDiffClamp'; +import AnimatedNode from '../../Animated/nodes/AnimatedNode'; + import * as React from 'react'; -import {useEffect, useMemo, useRef, useCallback} from 'react'; +import StyleSheet from '../../StyleSheet/StyleSheet'; +import View from '../View/View'; +import Platform from '../../Utilities/Platform'; + +import type {LayoutEvent} from '../../Types/CoreEventTypes'; -const AnimatedView = Animated.View; +const AnimatedView = AnimatedImplementation.createAnimatedComponent(View); export type Props = $ReadOnly<{ - children?: React.Element<$FlowFixMe>, + children?: React.Element, nextHeaderLayoutY: ?number, onLayout: (event: LayoutEvent) => void, - scrollAnimatedValue: Animated.Value, + scrollAnimatedValue: AnimatedImplementation.Value, // Will cause sticky headers to stick at the bottom of the ScrollView instead // of the top. inverted: ?boolean, @@ -32,275 +36,287 @@ export type Props = $ReadOnly<{ hiddenOnScroll?: ?boolean, }>; -const ScrollViewStickyHeaderWithForwardedRef: React.AbstractComponent< - Props, - $ReadOnly<{ - setNextHeaderY: number => void, - ...$Exact>, - }>, -> = React.forwardRef(function ScrollViewStickyHeader(props, forwardedRef) { - const { - inverted, - scrollViewHeight, - hiddenOnScroll, - scrollAnimatedValue, - nextHeaderLayoutY: _nextHeaderLayoutY, - } = props; +type State = { + measured: boolean, + layoutY: number, + layoutHeight: number, + nextHeaderLayoutY: ?number, + translateY: ?number, + ... +}; - const [measured, setMeasured] = React.useState(false); - const [layoutY, setLayoutY] = React.useState(0); - const [layoutHeight, setLayoutHeight] = React.useState(0); - const [translateY, setTranslateY] = React.useState(null); - const [nextHeaderLayoutY, setNextHeaderLayoutY] = React.useState( - _nextHeaderLayoutY, - ); - const [isFabric, setIsFabric] = React.useState(false); +class ScrollViewStickyHeader extends React.Component { + state: State = { + measured: false, + layoutY: 0, + layoutHeight: 0, + nextHeaderLayoutY: this.props.nextHeaderLayoutY, + translateY: null, + }; - const componentRef = React.useRef>(); - const _setNativeRef = setAndForwardRef({ - getForwardedRef: () => forwardedRef, - setLocalRef: ref => { - componentRef.current = ref; - if (ref) { - ref.setNextHeaderY = value => { - setNextHeaderLayoutY(value); - }; - setIsFabric( - !!( - // An internal transform mangles variables with leading "_" as private. - // eslint-disable-next-line dot-notation - ref['_internalInstanceHandle']?.stateNode?.canonical - ), - ); - } - }, - }); + _translateY: ?AnimatedNode = null; + _shouldRecreateTranslateY: boolean = true; + _haveReceivedInitialZeroTranslateY: boolean = true; + _ref: any; // TODO T53738161: flow type this, and the whole file - const offset = useMemo( - () => - hiddenOnScroll === true - ? Animated.diffClamp( - scrollAnimatedValue - .interpolate({ - extrapolateLeft: 'clamp', - inputRange: [layoutY, layoutY + 1], - outputRange: ([0, 1]: Array), - }) - .interpolate({ - inputRange: [0, 1], - outputRange: ([0, -1]: Array), - }), - -layoutHeight, - 0, - ) - : null, - [scrollAnimatedValue, layoutHeight, layoutY, hiddenOnScroll], - ); + // Fabric-only: + _timer: ?TimeoutID; + _animatedValueListenerId: string; + _animatedValueListener: (valueObject: $ReadOnly<{|value: number|}>) => void; + _debounceTimeout: number = Platform.OS === 'android' ? 15 : 64; - const [ - animatedTranslateY, - setAnimatedTranslateY, - ] = React.useState(() => { - const inputRange: Array = [-1, 0]; - const outputRange: Array = [0, 0]; - const initialTranslateY: Animated.Interpolation = scrollAnimatedValue.interpolate( - { - inputRange, - outputRange, - }, - ); + setNextHeaderY: (y: number) => void = (y: number): void => { + this._shouldRecreateTranslateY = true; + this.setState({nextHeaderLayoutY: y}); + }; - if (offset != null) { - return Animated.add(initialTranslateY, offset); + componentWillUnmount() { + if (this._translateY != null && this._animatedValueListenerId != null) { + this._translateY.removeListener(this._animatedValueListenerId); + } + if (this._timer) { + clearTimeout(this._timer); } - return initialTranslateY; - }); + } - const _haveReceivedInitialZeroTranslateY = useRef(true); - const _timer = useRef(null); + UNSAFE_componentWillReceiveProps(nextProps: Props) { + if ( + nextProps.scrollViewHeight !== this.props.scrollViewHeight || + nextProps.scrollAnimatedValue !== this.props.scrollAnimatedValue || + nextProps.inverted !== this.props.inverted + ) { + this._shouldRecreateTranslateY = true; + } + } - useEffect(() => { - if (translateY !== 0 && translateY != null) { - _haveReceivedInitialZeroTranslateY.current = false; + updateTranslateListener( + translateY: AnimatedImplementation.Interpolation, + isFabric: boolean, + offset: AnimatedDiffClamp | null, + ) { + if (this._translateY != null && this._animatedValueListenerId != null) { + this._translateY.removeListener(this._animatedValueListenerId); } - }, [translateY]); + offset + ? (this._translateY = new AnimatedAddition(translateY, offset)) + : (this._translateY = translateY); - // This is called whenever the (Interpolated) Animated Value - // updates, which is several times per frame during scrolling. - // To ensure that the Fabric ShadowTree has the most recent - // translate style of this node, we debounce the value and then - // pass it through to the underlying node during render. - // This is: - // 1. Only an issue in Fabric. - // 2. Worse in Android than iOS. In Android, but not iOS, you - // can touch and move your finger slightly and still trigger - // a "tap" event. In iOS, moving will cancel the tap in - // both Fabric and non-Fabric. On Android when you move - // your finger, the hit-detection moves from the Android - // platform to JS, so we need the ShadowTree to have knowledge - // of the current position. - const animatedValueListener = useCallback( - ({value}) => { - const _debounceTimeout: number = Platform.OS === 'android' ? 15 : 64; - // When the AnimatedInterpolation is recreated, it always initializes - // to a value of zero and emits a value change of 0 to its listeners. - if (value === 0 && !_haveReceivedInitialZeroTranslateY.current) { - _haveReceivedInitialZeroTranslateY.current = true; - return; - } - if (_timer.current != null) { - clearTimeout(_timer.current); - } - _timer.current = setTimeout(() => { - if (value !== translateY) { - setTranslateY(value); - } - }, _debounceTimeout); - }, - [translateY], - ); + this._shouldRecreateTranslateY = false; - useEffect(() => { - const inputRange: Array = [-1, 0]; - const outputRange: Array = [0, 0]; + if (!isFabric) { + return; + } - if (measured) { - if (inverted === true) { - // The interpolation looks like: - // - Negative scroll: no translation - // - `stickStartPoint` is the point at which the header will start sticking. - // It is calculated using the ScrollView viewport height so it is a the bottom. - // - Headers that are in the initial viewport will never stick, `stickStartPoint` - // will be negative. - // - From 0 to `stickStartPoint` no translation. This will cause the header - // to scroll normally until it reaches the top of the scroll view. - // - From `stickStartPoint` to when the next header y hits the bottom edge of the header: translate - // equally to scroll. This will cause the header to stay at the top of the scroll view. - // - Past the collision with the next header y: no more translation. This will cause the - // header to continue scrolling up and make room for the next sticky header. - // In the case that there is no next header just translate equally to - // scroll indefinitely. - if (scrollViewHeight != null) { - const stickStartPoint = layoutY + layoutHeight - scrollViewHeight; - if (stickStartPoint > 0) { - inputRange.push(stickStartPoint); - outputRange.push(0); - inputRange.push(stickStartPoint + 1); - outputRange.push(1); - // If the next sticky header has not loaded yet (probably windowing) or is the last - // we can just keep it sticked forever. - const collisionPoint = - (nextHeaderLayoutY || 0) - layoutHeight - scrollViewHeight; - if (collisionPoint > stickStartPoint) { - inputRange.push(collisionPoint, collisionPoint + 1); - outputRange.push( - collisionPoint - stickStartPoint, - collisionPoint - stickStartPoint, - ); - } - } + if (!this._animatedValueListener) { + // This is called whenever the (Interpolated) Animated Value + // updates, which is several times per frame during scrolling. + // To ensure that the Fabric ShadowTree has the most recent + // translate style of this node, we debounce the value and then + // pass it through to the underlying node during render. + // This is: + // 1. Only an issue in Fabric. + // 2. Worse in Android than iOS. In Android, but not iOS, you + // can touch and move your finger slightly and still trigger + // a "tap" event. In iOS, moving will cancel the tap in + // both Fabric and non-Fabric. On Android when you move + // your finger, the hit-detection moves from the Android + // platform to JS, so we need the ShadowTree to have knowledge + // of the current position. + this._animatedValueListener = ({value}) => { + // When the AnimatedInterpolation is recreated, it always initializes + // to a value of zero and emits a value change of 0 to its listeners. + if (value === 0 && !this._haveReceivedInitialZeroTranslateY) { + this._haveReceivedInitialZeroTranslateY = true; + return; } - } else { - // The interpolation looks like: - // - Negative scroll: no translation - // - From 0 to the y of the header: no translation. This will cause the header - // to scroll normally until it reaches the top of the scroll view. - // - From header y to when the next header y hits the bottom edge of the header: translate - // equally to scroll. This will cause the header to stay at the top of the scroll view. - // - Past the collision with the next header y: no more translation. This will cause the - // header to continue scrolling up and make room for the next sticky header. - // In the case that there is no next header just translate equally to - // scroll indefinitely. - inputRange.push(layoutY); - outputRange.push(0); - // If the next sticky header has not loaded yet (probably windowing) or is the last - // we can just keep it sticked forever. - const collisionPoint = (nextHeaderLayoutY || 0) - layoutHeight; - if (collisionPoint >= layoutY) { - inputRange.push(collisionPoint, collisionPoint + 1); - outputRange.push(collisionPoint - layoutY, collisionPoint - layoutY); - } else { - inputRange.push(layoutY + 1); - outputRange.push(1); + if (this._timer) { + clearTimeout(this._timer); } - } - } - - let newAnimatedTranslateY: Animated.Node = scrollAnimatedValue.interpolate({ - inputRange, - outputRange, - }); - - if (offset != null) { - newAnimatedTranslateY = Animated.add(newAnimatedTranslateY, offset); + this._timer = setTimeout(() => { + if (value !== this.state.translateY) { + this.setState({ + translateY: value, + }); + } + }, this._debounceTimeout); + }; } - - // add the event listener - let animatedListenerId; - if (isFabric) { - animatedListenerId = newAnimatedTranslateY.addListener( - animatedValueListener, - ); + if (this.state.translateY !== 0 && this.state.translateY != null) { + this._haveReceivedInitialZeroTranslateY = false; } + this._animatedValueListenerId = translateY.addListener( + this._animatedValueListener, + ); + } - setAnimatedTranslateY(newAnimatedTranslateY); + _onLayout = event => { + const layoutY = event.nativeEvent.layout.y; + const layoutHeight = event.nativeEvent.layout.height; + const measured = true; - // clean up the event listener and timer - return () => { - if (animatedListenerId) { - newAnimatedTranslateY.removeListener(animatedListenerId); - } - if (_timer.current != null) { - clearTimeout(_timer.current); - } - }; - }, [nextHeaderLayoutY, measured, layoutHeight, layoutY, scrollViewHeight, scrollAnimatedValue, inverted, offset, animatedValueListener, isFabric]); + if ( + layoutY !== this.state.layoutY || + layoutHeight !== this.state.layoutHeight || + measured !== this.state.measured + ) { + this._shouldRecreateTranslateY = true; + } - const _onLayout = (event: LayoutEvent) => { - setLayoutY(event.nativeEvent.layout.y); - setLayoutHeight(event.nativeEvent.layout.height); - setMeasured(true); + this.setState({ + measured, + layoutY, + layoutHeight, + }); - props.onLayout(event); - const child = React.Children.only(props.children); + this.props.onLayout(event); + const child = React.Children.only(this.props.children); if (child.props.onLayout) { child.props.onLayout(event); } }; - const child = React.Children.only(props.children); + _setComponentRef = ref => { + this._ref = ref; + }; + + render(): React.Node { + // Fabric Detection + const isFabric = !!( + // An internal transform mangles variables with leading "_" as private. + // eslint-disable-next-line dot-notation + (this._ref && this._ref['_internalInstanceHandle']?.stateNode?.canonical) + ); + // Initially and in the case of updated props or layout, we + // recreate this interpolated value. Otherwise, we do not recreate + // when there are state changes. + if (this._shouldRecreateTranslateY) { + const {inverted, scrollViewHeight} = this.props; + const {measured, layoutHeight, layoutY, nextHeaderLayoutY} = this.state; + const inputRange: Array = [-1, 0]; + const outputRange: Array = [0, 0]; - // TODO T68319535: remove this if NativeAnimated is rewritten for Fabric - const passthroughAnimatedPropExplicitValues = - isFabric && translateY != null - ? { - style: {transform: [{translateY: translateY}]}, + if (measured) { + if (inverted) { + // The interpolation looks like: + // - Negative scroll: no translation + // - `stickStartPoint` is the point at which the header will start sticking. + // It is calculated using the ScrollView viewport height so it is a the bottom. + // - Headers that are in the initial viewport will never stick, `stickStartPoint` + // will be negative. + // - From 0 to `stickStartPoint` no translation. This will cause the header + // to scroll normally until it reaches the top of the scroll view. + // - From `stickStartPoint` to when the next header y hits the bottom edge of the header: translate + // equally to scroll. This will cause the header to stay at the top of the scroll view. + // - Past the collision with the next header y: no more translation. This will cause the + // header to continue scrolling up and make room for the next sticky header. + // In the case that there is no next header just translate equally to + // scroll indefinitely. + if (scrollViewHeight != null) { + const stickStartPoint = layoutY + layoutHeight - scrollViewHeight; + if (stickStartPoint > 0) { + inputRange.push(stickStartPoint); + outputRange.push(0); + inputRange.push(stickStartPoint + 1); + outputRange.push(1); + // If the next sticky header has not loaded yet (probably windowing) or is the last + // we can just keep it sticked forever. + const collisionPoint = + (nextHeaderLayoutY || 0) - layoutHeight - scrollViewHeight; + if (collisionPoint > stickStartPoint) { + inputRange.push(collisionPoint, collisionPoint + 1); + outputRange.push( + collisionPoint - stickStartPoint, + collisionPoint - stickStartPoint, + ); + } + } + } + } else { + // The interpolation looks like: + // - Negative scroll: no translation + // - From 0 to the y of the header: no translation. This will cause the header + // to scroll normally until it reaches the top of the scroll view. + // - From header y to when the next header y hits the bottom edge of the header: translate + // equally to scroll. This will cause the header to stay at the top of the scroll view. + // - Past the collision with the next header y: no more translation. This will cause the + // header to continue scrolling up and make room for the next sticky header. + // In the case that there is no next header just translate equally to + // scroll indefinitely. + inputRange.push(layoutY); + outputRange.push(0); + // If the next sticky header has not loaded yet (probably windowing) or is the last + // we can just keep it sticked forever. + const collisionPoint = (nextHeaderLayoutY || 0) - layoutHeight; + if (collisionPoint >= layoutY) { + inputRange.push(collisionPoint, collisionPoint + 1); + outputRange.push( + collisionPoint - layoutY, + collisionPoint - layoutY, + ); + } else { + inputRange.push(layoutY + 1); + outputRange.push(1); + } } - : null; + } - return ( - /* $FlowFixMe[prop-missing] passthroughAnimatedPropExplicitValues isn't properly - included in the Animated.View flow type. */ - - {React.cloneElement(child, { - style: styles.fill, // We transfer the child style to the wrapper. - onLayout: undefined, // we call this manually through our this._onLayout - })} - - ); -}); + this.updateTranslateListener( + this.props.scrollAnimatedValue.interpolate({ + inputRange, + outputRange, + }), + isFabric, + this.props.hiddenOnScroll + ? new AnimatedDiffClamp( + this.props.scrollAnimatedValue + .interpolate({ + extrapolateLeft: 'clamp', + inputRange: [layoutY, layoutY + 1], + outputRange: ([0, 1]: Array), + }) + .interpolate({ + inputRange: [0, 1], + outputRange: ([0, -1]: Array), + }), + -this.state.layoutHeight, + 0, + ) + : null, + ); + } + + const child = React.Children.only(this.props.children); + + // TODO T68319535: remove this if NativeAnimated is rewritten for Fabric + const passthroughAnimatedPropExplicitValues = + isFabric && this.state.translateY != null + ? { + style: {transform: [{translateY: this.state.translateY}]}, + } + : null; + + return ( + + {React.cloneElement(child, { + style: styles.fill, // We transfer the child style to the wrapper. + onLayout: undefined, // we call this manually through our this._onLayout + })} + + ); + } +} const styles = StyleSheet.create({ header: { @@ -312,4 +328,4 @@ const styles = StyleSheet.create({ }, }); -export default ScrollViewStickyHeaderWithForwardedRef; +module.exports = ScrollViewStickyHeader; diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h index 70a20f0b00f632..9dd96a5cd140d2 100644 --- a/React/Base/RCTBridge+Private.h +++ b/React/Base/RCTBridge+Private.h @@ -7,6 +7,7 @@ #import +@class RCTModuleRegistry; @class RCTModuleData; @protocol RCTJavaScriptExecutor; @@ -62,6 +63,13 @@ RCT_EXTERN void RCTRegisterModule(Class); */ @property (nonatomic, strong, readwrite) NSURL *bundleURL; +/** + * An object that allows one to require NativeModules/TurboModules. + * RCTModuleRegistry is implemented in bridgeless mode and bridge mode. + * Used by RCTRootView. + */ +@property (nonatomic, strong, readonly) RCTModuleRegistry *moduleRegistry; + @end @interface RCTBridge (RCTCxxBridge) diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 850c78c135adea..10503261d72b96 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -257,6 +257,11 @@ - (void)didReceiveReloadCommand }); } +- (RCTModuleRegistry *)moduleRegistry +{ + return self.batchedBridge.moduleRegistry; +} + - (NSArray *)moduleClasses { return self.batchedBridge.moduleClasses; diff --git a/React/Base/RCTEventDispatcherProtocol.h b/React/Base/RCTEventDispatcherProtocol.h index 9e54ccbf187ed8..913cf85228356b 100644 --- a/React/Base/RCTEventDispatcherProtocol.h +++ b/React/Base/RCTEventDispatcherProtocol.h @@ -81,6 +81,8 @@ typedef NS_ENUM(NSInteger, RCTTextEventType) { */ @protocol RCTEventDispatcherProtocol +- (void)sendViewEventWithName:(NSString *)name reactTag:(NSNumber *)reactTag; + /** * Deprecated, do not use. */ diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h index f555e234c71395..dd563453153110 100644 --- a/React/Base/RCTRootView.h +++ b/React/Base/RCTRootView.h @@ -8,6 +8,8 @@ #import #import +#import +#import @protocol RCTRootViewDelegate; @@ -75,6 +77,19 @@ extern initialProperties:(nullable NSDictionary *)initialProperties launchOptions:(nullable NSDictionary *)launchOptions; +/** + * This API allows RCTRootView users to know if the root view is backed by the bridge. + */ +@property (nonatomic, readonly) BOOL hasBridge; + +/** + * This API allows users of RCTRootView to access other NativeModules, without + * directly accessing the bridge. + */ +@property (nonatomic, strong, readonly) RCTModuleRegistry *moduleRegistry; + +@property (nonatomic, strong, readonly) id eventDispatcher; + /** * The name of the JavaScript module to execute within the * specified scriptURL (required). Setting this will not have diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 7e8a3804d1db65..4da26ee42b1093 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -116,6 +116,21 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) +- (BOOL)hasBridge +{ + return _bridge != nil; +} + +- (RCTModuleRegistry *)moduleRegistry +{ + return _bridge.moduleRegistry; +} + +- (id)eventDispatcher +{ + return [self.moduleRegistry moduleForName:"EventDispatcher"]; +} + #pragma mark - passThroughTouches - (BOOL)passThroughTouches diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h index 8e34cd7583c226..7a42041d0fdc18 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h @@ -26,6 +26,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy, readonly) NSString *moduleName; @property (nonatomic, strong, readonly) RCTBridge *bridge; +@property (nonatomic, readonly) BOOL hasBridge; +@property (nonatomic, strong, readonly) RCTModuleRegistry *moduleRegistry; +@property (nonatomic, strong, readonly) id eventDispatcher; @property (nonatomic, copy, readwrite) NSDictionary *appProperties; @property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility; @property (nonatomic, weak) id delegate; diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm index 50f4e745fb167e..ad12ace6ddc5a5 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm @@ -10,6 +10,7 @@ #import #import "RCTAssert.h" +#import "RCTBridge+Private.h" #import "RCTBridge.h" #import "RCTLog.h" #import "RCTPerformanceLogger.h" @@ -93,6 +94,21 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; } +- (BOOL)hasBridge +{ + return _bridge != nil; +} + +- (RCTModuleRegistry *)moduleRegistry +{ + return _bridge.moduleRegistry; +} + +- (id)eventDispatcher +{ + return [self.moduleRegistry moduleForName:"EventDispatcher"]; +} + RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) diff --git a/React/CoreModules/RCTEventDispatcher.mm b/React/CoreModules/RCTEventDispatcher.mm index d9c690538967b0..5b2dad2d61baaa 100644 --- a/React/CoreModules/RCTEventDispatcher.mm +++ b/React/CoreModules/RCTEventDispatcher.mm @@ -56,6 +56,11 @@ - (void)initialize _observersLock = [NSLock new]; } +- (void)sendViewEventWithName:(NSString *)name reactTag:(NSNumber *)reactTag +{ + [_callableJSModules invokeModule:@"RCTViewEventEmitter" method:@"emit" withArgs:@[ name, RCTNullIfNil(reactTag) ]]; +} + - (void)sendAppEventWithName:(NSString *)name body:(id)body { [_callableJSModules invokeModule:@"RCTNativeAppEventEmitter" diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index 0f1a601f4a6ec0..a33b656d9cfb4e 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -244,6 +244,11 @@ @implementation RCTCxxBridge { @synthesize performanceLogger = _performanceLogger; @synthesize valid = _valid; +- (RCTModuleRegistry *)moduleRegistry +{ + return _objCModuleRegistry; +} + - (void)setRCTTurboModuleRegistry:(id)turboModuleRegistry { _turboModuleRegistry = turboModuleRegistry; diff --git a/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutorFactory.java b/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutorFactory.java index 976af80b1eeb66..ce09abba961109 100644 --- a/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutorFactory.java +++ b/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutorFactory.java @@ -17,7 +17,7 @@ public class HermesExecutorFactory implements JavaScriptExecutorFactory { private final RuntimeConfig mConfig; public HermesExecutorFactory() { - this(new RuntimeConfig(1024)); + this(null); } public HermesExecutorFactory(RuntimeConfig config) { diff --git a/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/RuntimeConfig.java b/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/RuntimeConfig.java index fec7c457bc8b98..a3e91b8cce6ff9 100644 --- a/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/RuntimeConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/RuntimeConfig.java @@ -10,10 +10,4 @@ /** Holds runtime configuration for a Hermes VM instance (master or snapshot). */ public final class RuntimeConfig { public long heapSizeMB; - - RuntimeConfig() {} - - RuntimeConfig(long heapSizeMB) { - this.heapSizeMB = heapSizeMB; - } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 4c8a8f97977f6c..6df4dd1bd976bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1360,6 +1360,10 @@ private ReactApplicationContext createReactContext( } } + if (ReactFeatureFlags.enableRuntimeScheduler) { + catalystInstance.installRuntimeScheduler(); + } + if (mJSIModulePackage != null) { catalystInstance.addJSIModules( mJSIModulePackage.getJSIModules( diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java index 1a5067b7edb358..09eb2c70183682 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java @@ -111,6 +111,10 @@ public interface CatalystInstance RuntimeExecutor getRuntimeExecutor(); + RuntimeScheduler getRuntimeScheduler(); + + void installRuntimeScheduler(); + void addJSIModules(List jsiModules); /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index baffa40aabbe83..d5a9b97571b76f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -558,6 +558,10 @@ public JavaScriptContextHolder getJavaScriptContextHolder() { public native RuntimeExecutor getRuntimeExecutor(); + public native RuntimeScheduler getRuntimeScheduler(); + + public native void installRuntimeScheduler(); + @Override public void addJSIModules(List jsiModules) { mJSIModuleRegistry.registerModules(jsiModules); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/RuntimeScheduler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/RuntimeScheduler.java new file mode 100644 index 00000000000000..7270c65c6bfa1f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/RuntimeScheduler.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) Facebook, Inc. and its 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.bridge; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; + +/** A Java holder for a C++ RuntimeScheduler. */ +public class RuntimeScheduler { + + @DoNotStrip private HybridData mHybridData; + + public RuntimeScheduler(HybridData hybridData) { + mHybridData = hybridData; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index 6449ef07579550..e02f4188f5d16e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -9,11 +9,13 @@ import android.annotation.SuppressLint; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.react.bridge.NativeMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.RuntimeExecutor; +import com.facebook.react.bridge.RuntimeScheduler; import com.facebook.react.bridge.queue.MessageQueueThread; import com.facebook.react.fabric.events.EventBeatManager; import com.facebook.react.fabric.events.EventEmitterWrapper; @@ -37,6 +39,7 @@ public Binding() { private native void installFabricUIManager( RuntimeExecutor runtimeExecutor, + RuntimeScheduler runtimeScheduler, Object uiManager, EventBeatManager eventBeatManager, MessageQueueThread jsMessageQueueThread, @@ -83,6 +86,7 @@ public native ReadableNativeMap getInspectorDataForInstance( public void register( @NonNull RuntimeExecutor runtimeExecutor, + @Nullable RuntimeScheduler runtimeScheduler, @NonNull FabricUIManager fabricUIManager, @NonNull EventBeatManager eventBeatManager, @NonNull MessageQueueThread jsMessageQueueThread, @@ -91,6 +95,7 @@ public void register( fabricUIManager.setBinding(this); installFabricUIManager( runtimeExecutor, + runtimeScheduler, fabricUIManager, eventBeatManager, jsMessageQueueThread, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index 84bea4d85f6181..c4a6fbfb5c71b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -55,6 +55,7 @@ public UIManager get() { binding.register( mReactApplicationContext.getCatalystInstance().getRuntimeExecutor(), + mReactApplicationContext.getCatalystInstance().getRuntimeScheduler(), uiManager, eventBeatManager, jsMessageQueueThread, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index 2ad53b97cc2cee..1c2bde705d6f19 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libjsi libreactconfig librrc_slider librrc_progressbar librrc_switch librrc_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core react_render_componentregistry librrc_view librrc_unimplementedview librrc_root librrc_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_codegen_rncore rrc_text librrc_image librrc_textinput libreact_debug libreact_render_mapbuffer libmapbufferjni libreact_render_telemetry +LOCAL_SHARED_LIBRARIES := libjsi libreactconfig librrc_slider librrc_progressbar librrc_switch librrc_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core react_render_componentregistry librrc_view librrc_unimplementedview librrc_root librrc_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_codegen_rncore rrc_text librrc_image librrc_textinput libreact_debug libreact_render_mapbuffer libmapbufferjni libreact_render_telemetry libreact_render_runtimescheduler LOCAL_STATIC_LIBRARIES := @@ -56,6 +56,7 @@ $(call import-module,react/renderer/graphics) $(call import-module,react/renderer/imagemanager) $(call import-module,react/renderer/mapbuffer) $(call import-module,react/renderer/mounting) +$(call import-module,react/renderer/runtimescheduler) $(call import-module,react/renderer/scheduler) $(call import-module,react/renderer/templateprocessor) $(call import-module,react/renderer/textlayoutmanager) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index d7fb074d31ccd5..7c9d43bee01dd3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -493,6 +493,7 @@ bool isMapBufferSerializationEnabled() { void Binding::installFabricUIManager( jni::alias_ref runtimeExecutorHolder, + jni::alias_ref runtimeSchedulerHolder, jni::alias_ref javaUIManager, EventBeatManager *eventBeatManager, jni::alias_ref jsMessageQueueThread, @@ -527,6 +528,19 @@ void Binding::installFabricUIManager( std::make_shared(jsMessageQueueThread); auto runtimeExecutor = runtimeExecutorHolder->cthis()->get(); + if (runtimeSchedulerHolder) { + auto runtimeScheduler = runtimeSchedulerHolder->cthis()->get(); + if (runtimeScheduler) { + runtimeScheduler->setEnableYielding(config->getBool( + "react_native_new_architecture:runtimescheduler_enable_yielding_android")); + runtimeExecutor = + [runtimeScheduler]( + std::function &&callback) { + runtimeScheduler->scheduleWork(std::move(callback)); + }; + } + } + // TODO: T31905686 Create synchronous Event Beat jni::global_ref localJavaUIManager = javaUIManager_; EventBeat::Factory synchronousBeatFactory = diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index d3045b0e1b1a43..5ae4f0189e29ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,7 @@ class Binding : public jni::HybridClass, void installFabricUIManager( jni::alias_ref runtimeExecutorHolder, + jni::alias_ref runtimeSchedulerHolder, jni::alias_ref javaUIManager, EventBeatManager *eventBeatManager, jni::alias_ref jsMessageQueueThread, diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 82445d00ec04d2..af2077b5a66319 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -27,7 +27,7 @@ LOCAL_CFLAGS += -fexceptions -frtti -Wno-unused-lambda-capture LOCAL_LDLIBS += -landroid # The dynamic libraries (.so files) that this module depends on. -LOCAL_SHARED_LIBRARIES := libfolly_json libfb libfbjni libglog_init libyoga +LOCAL_SHARED_LIBRARIES := libfolly_json libfb libfbjni libglog_init libyoga libreact_render_runtimescheduler # The static libraries (.a files) that this module depends on. LOCAL_STATIC_LIBRARIES := libreactnative libcallinvokerholder libruntimeexecutor @@ -77,7 +77,7 @@ LOCAL_CFLAGS += -fexceptions -frtti -Wno-unused-lambda-capture LOCAL_LDLIBS += -landroid # The dynamic libraries (.so files) that this module depends on. -LOCAL_SHARED_LIBRARIES := libreactnativeutilsjni libfolly_json libfb libfbjni libglog_init libyoga logger +LOCAL_SHARED_LIBRARIES := libreactnativeutilsjni libfolly_json libfb libfbjni libglog_init libyoga logger libreact_render_runtimescheduler # The static libraries (.a files) that this module depends on. LOCAL_STATIC_LIBRARIES := libreactnative libruntimeexecutor libcallinvokerholder @@ -129,6 +129,7 @@ $(call import-module,callinvoker) $(call import-module,reactperflogger) $(call import-module,hermes) $(call import-module,runtimeexecutor) +$(call import-module,react/renderer/runtimescheduler) $(call import-module,react/nativemodule/core) include $(REACT_SRC_DIR)/reactperflogger/jni/Android.mk diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index dc88910cf425ee..99160d55a3c45e 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -20,6 +20,7 @@ EXPORTED_HEADERS = [ "ReadableNativeArray.h", "ReadableNativeMap.h", "JRuntimeExecutor.h", + "JRuntimeScheduler.h", "WritableNativeArray.h", "WritableNativeMap.h", ] @@ -67,6 +68,7 @@ rn_xplat_cxx_library( react_native_xplat_target("cxxreact:module"), react_native_xplat_target("jsinspector:jsinspector"), react_native_xplat_target("runtimeexecutor:runtimeexecutor"), + react_native_xplat_target("react/renderer/runtimescheduler:runtimescheduler"), react_native_xplat_target("logger:logger"), react_native_xplat_dep("jsi:jsi"), FBJNI_TARGET, diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 6b1f09f2720f58..e5b36b30dd1a22 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include @@ -136,6 +138,11 @@ void CatalystInstanceImpl::registerNatives() { CatalystInstanceImpl::handleMemoryPressure), makeNativeMethod( "getRuntimeExecutor", CatalystInstanceImpl::getRuntimeExecutor), + makeNativeMethod( + "getRuntimeScheduler", CatalystInstanceImpl::getRuntimeScheduler), + makeNativeMethod( + "installRuntimeScheduler", + CatalystInstanceImpl::installRuntimeScheduler), makeNativeMethod( "warnOnLegacyNativeModuleSystemUse", CatalystInstanceImpl::warnOnLegacyNativeModuleSystemUse), @@ -388,5 +395,25 @@ CatalystInstanceImpl::getRuntimeExecutor() { return runtimeExecutor_; } +jni::alias_ref +CatalystInstanceImpl::getRuntimeScheduler() { + return runtimeScheduler_; +} + +void CatalystInstanceImpl::installRuntimeScheduler() { + if (!runtimeScheduler_) { + auto runtimeExecutor = instance_->getRuntimeExecutor(); + auto runtimeScheduler = std::make_shared(runtimeExecutor); + + runtimeScheduler_ = + jni::make_global(JRuntimeScheduler::newObjectCxxArgs(runtimeScheduler)); + + runtimeExecutor([runtimeScheduler](jsi::Runtime &runtime) { + RuntimeSchedulerBinding::createAndInstallIfNeeded( + runtime, runtimeScheduler); + }); + } +} + } // namespace react } // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index cc4006b26b07c4..66daec3e34b05c 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -15,6 +15,7 @@ #include "CxxModuleWrapper.h" #include "JMessageQueueThread.h" #include "JRuntimeExecutor.h" +#include "JRuntimeScheduler.h" #include "JSLoader.h" #include "JavaModuleWrapper.h" #include "ModuleRegistryBuilder.h" @@ -98,6 +99,8 @@ class CatalystInstanceImpl : public jni::HybridClass { jni::alias_ref getJSCallInvokerHolder(); jni::alias_ref getNativeCallInvokerHolder(); jni::alias_ref getRuntimeExecutor(); + jni::alias_ref getRuntimeScheduler(); + void installRuntimeScheduler(); void setGlobalVariable(std::string propName, std::string &&jsonValue); jlong getJavaScriptContext(); void handleMemoryPressure(int pressureLevel); @@ -110,6 +113,7 @@ class CatalystInstanceImpl : public jni::HybridClass { jni::global_ref jsCallInvokerHolder_; jni::global_ref nativeCallInvokerHolder_; jni::global_ref runtimeExecutor_; + jni::global_ref runtimeScheduler_; }; } // namespace react diff --git a/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp b/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp new file mode 100644 index 00000000000000..3b059ec89c1efc --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "JRuntimeScheduler.h" + +namespace facebook { +namespace react { + +JRuntimeScheduler::JRuntimeScheduler( + std::shared_ptr const &runtimeScheduler) + : runtimeScheduler_(runtimeScheduler) {} + +std::shared_ptr JRuntimeScheduler::get() { + return runtimeScheduler_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h b/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h new file mode 100644 index 00000000000000..fb58c7ef7775cc --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) Facebook, Inc. and its 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 +#include + +namespace facebook { +namespace react { + +class JRuntimeScheduler : public jni::HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Lcom/facebook/react/bridge/RuntimeScheduler;"; + + std::shared_ptr get(); + + private: + friend HybridBase; + JRuntimeScheduler(std::shared_ptr const &runtimeScheduler); + std::shared_ptr runtimeScheduler_; +}; + +} // namespace react +} // namespace facebook diff --git a/gradle.properties b/gradle.properties index e785ec12c912ef..223dcfb79c24c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ org.gradle.parallel=true ANDROID_NDK_VERSION=21.4.7075529 android.useAndroidX=true -kotlin_version=1.4.21 +kotlin_version=1.4.32 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 29e41345763549..af7be50b1015cb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index ac1b06f93825db..00000000000000 --- a/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/package.json b/package.json index f8d1e77291223d..97747f06de0c3d 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "anser": "^1.4.9", "base64-js": "^1.1.2", "event-target-shim": "^5.0.1", - "hermes-engine": "~0.8.0", + "hermes-engine": "~0.9.0", "invariant": "^2.2.4", "jsc-android": "^250230.2.1", "metro-babel-register": "0.66.2", @@ -121,7 +121,7 @@ "ws": "^6.1.4" }, "devDependencies": { - "flow-bin": "^0.158.0", + "flow-bin": "^0.159.0", "react": "17.0.2" }, "detox": { diff --git a/packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties b/packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties index 29e41345763549..af7be50b1015cb 100644 --- a/packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/packages/react-native-codegen/android/gradlew.bat b/packages/react-native-codegen/android/gradlew.bat deleted file mode 100644 index ac1b06f93825db..00000000000000 --- a/packages/react-native-codegen/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/packages/react-native-gradle-plugin/build.gradle.kts b/packages/react-native-gradle-plugin/build.gradle.kts index 75a8bb54da3fb9..4dc4d68f7b2d26 100644 --- a/packages/react-native-gradle-plugin/build.gradle.kts +++ b/packages/react-native-gradle-plugin/build.gradle.kts @@ -6,8 +6,8 @@ */ plugins { - `java-gradle-plugin` - `kotlin-dsl` + kotlin("jvm") version "1.4.21" + id("java-gradle-plugin") } repositories { @@ -25,5 +25,6 @@ gradlePlugin { } dependencies { + implementation(gradleApi()) implementation("com.android.tools.build:gradle:4.2.2") } diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000000..7454180f2ae884 Binary files /dev/null and b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000000..af7be50b1015cb --- /dev/null +++ b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/react-native-gradle-plugin/gradlew b/packages/react-native-gradle-plugin/gradlew new file mode 100755 index 00000000000000..744e882ed57263 --- /dev/null +++ b/packages/react-native-gradle-plugin/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/packages/react-native-gradle-plugin/settings.gradle.kts b/packages/react-native-gradle-plugin/settings.gradle.kts new file mode 100644 index 00000000000000..7e74af1ef9702a --- /dev/null +++ b/packages/react-native-gradle-plugin/settings.gradle.kts @@ -0,0 +1,13 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +pluginManagement { + repositories { + gradlePluginPortal() + google() + } +} diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/AndroidConfiguration.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/AndroidConfiguration.kt index 0e5cf8f75f273e..b7de384df6d23b 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/AndroidConfiguration.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/AndroidConfiguration.kt @@ -16,7 +16,7 @@ fun Project.configureDevPorts(androidExt: BaseExtension) { project.properties["reactNativeInspectorProxyPort"]?.toString() ?: devServerPort androidExt.buildTypes.all { - resValue("integer", "react_native_dev_server_port", devServerPort) - resValue("integer", "react_native_inspector_proxy_port", inspectorProxyPort) + it.resValue("integer", "react_native_dev_server_port", devServerPort) + it.resValue("integer", "react_native_inspector_proxy_port", inspectorProxyPort) } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactAppPlugin.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactAppPlugin.kt index 7b06e9067d1314..54ff34e50950e4 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactAppPlugin.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactAppPlugin.kt @@ -12,25 +12,23 @@ import com.android.build.gradle.BaseExtension import com.android.build.gradle.LibraryExtension import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.getByType class ReactAppPlugin : Plugin { override fun apply(project: Project) { - val config = project.extensions.create("reactApp", project) + val config = project.extensions.create("reactApp", ReactAppExtension::class.java, project) project.afterEvaluate { - val androidConfiguration = extensions.getByType() - configureDevPorts(androidConfiguration) + val androidConfiguration = project.extensions.getByType(BaseExtension::class.java) + project.configureDevPorts(androidConfiguration) - val isAndroidLibrary = plugins.hasPlugin("com.android.library") + val isAndroidLibrary = project.plugins.hasPlugin("com.android.library") val variants = if (isAndroidLibrary) { - extensions.getByType().libraryVariants + project.extensions.getByType(LibraryExtension::class.java).libraryVariants } else { - extensions.getByType().applicationVariants + project.extensions.getByType(AppExtension::class.java).applicationVariants } - variants.all { configureReactTasks(variant = this, config = config) } + variants.all { project.configureReactTasks(variant = it, config = config) } } } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt index e518d780497ca8..d1a6b4be07bac6 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt @@ -16,8 +16,6 @@ import com.facebook.react.tasks.HermesBinaryTask import java.io.File import org.gradle.api.Project import org.gradle.api.tasks.Copy -import org.gradle.kotlin.dsl.extra -import org.gradle.kotlin.dsl.register private const val REACT_GROUP = "react" @@ -49,17 +47,17 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE val bundleEnabled = variant.checkBundleEnabled(config) val bundleTask = - tasks.register("createBundle${targetName}JsAndAssets") { - val task = this - task.group = REACT_GROUP - task.description = "create JS bundle and assets for $targetName." - - task.reactRoot = config.reactRoot - task.sources = fileTree(config.reactRoot) { setExcludes(config.inputExcludes) } - task.execCommand = execCommand - task.bundleCommand = config.bundleCommand - task.devEnabled = !(variant.name in config.devDisabledInVariants || isRelease) - task.entryFile = config.detectedEntryFile + tasks.register("createBundle${targetName}JsAndAssets", BundleJsAndAssetsTask::class.java) { + it.group = REACT_GROUP + it.description = "create JS bundle and assets for $targetName." + + it.reactRoot = config.reactRoot + it.sources = + fileTree(config.reactRoot) { fileTree -> fileTree.setExcludes(config.inputExcludes) } + it.execCommand = execCommand + it.bundleCommand = config.bundleCommand + it.devEnabled = !(variant.name in config.devDisabledInVariants || isRelease) + it.entryFile = config.detectedEntryFile val extraArgs = mutableListOf() @@ -69,56 +67,54 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE } // Hermes doesn't require JS minification. - if (enableHermes && !devEnabled) { + if (enableHermes && !it.devEnabled) { extraArgs.add("--minify") extraArgs.add("false") } extraArgs.addAll(config.extraPackagerArgs) - task.extraArgs = emptyList() + it.extraArgs = emptyList() - task.jsBundleDir = jsBundleDir - task.jsBundleFile = jsBundleFile - task.resourcesDir = resourcesDir - task.jsIntermediateSourceMapsDir = jsIntermediateSourceMapsDir - task.jsSourceMapsDir = jsSourceMapsDir - task.jsSourceMapsFile = if (enableHermes) jsPackagerSourceMapFile else jsOutputSourceMapFile + it.jsBundleDir = jsBundleDir + it.jsBundleFile = jsBundleFile + it.resourcesDir = resourcesDir + it.jsIntermediateSourceMapsDir = jsIntermediateSourceMapsDir + it.jsSourceMapsDir = jsSourceMapsDir + it.jsSourceMapsFile = if (enableHermes) jsPackagerSourceMapFile else jsOutputSourceMapFile - task.enabled = bundleEnabled + it.enabled = bundleEnabled } val hermesTask = - tasks.register("emit${targetName}HermesResources") { - val task = this - task.group = REACT_GROUP - task.description = "bundle hermes resources for $targetName" - - task.reactRoot = config.reactRoot - task.hermesCommand = config.osAwareHermesCommand - task.hermesFlags = if (isRelease) config.hermesFlagsRelease else config.hermesFlagsDebug - task.jsBundleFile = jsBundleFile - task.composeSourceMapsCommand = nodeExecutableAndArgs + config.composeSourceMapsPath - task.jsPackagerSourceMapFile = jsPackagerSourceMapFile - task.jsCompilerSourceMapFile = jsCompilerSourceMapFile - task.jsOutputSourceMapFile = jsOutputSourceMapFile - - task.dependsOn(bundleTask) - - task.enabled = bundleEnabled && enableHermes + tasks.register("emit${targetName}HermesResources", HermesBinaryTask::class.java) { + it.group = REACT_GROUP + it.description = "bundle hermes resources for $targetName" + + it.reactRoot = config.reactRoot + it.hermesCommand = config.osAwareHermesCommand + it.hermesFlags = if (isRelease) config.hermesFlagsRelease else config.hermesFlagsDebug + it.jsBundleFile = jsBundleFile + it.composeSourceMapsCommand = nodeExecutableAndArgs + config.composeSourceMapsPath + it.jsPackagerSourceMapFile = jsPackagerSourceMapFile + it.jsCompilerSourceMapFile = jsCompilerSourceMapFile + it.jsOutputSourceMapFile = jsOutputSourceMapFile + + it.dependsOn(bundleTask) + + it.enabled = bundleEnabled && enableHermes } val aggregatedBundleTask = tasks.register("bundle${targetName}JsAndAssets") { - val task = this - task.group = REACT_GROUP - task.description = "bundle JS and resources for $targetName" + it.group = REACT_GROUP + it.description = "bundle JS and resources for $targetName" - task.dependsOn(bundleTask, hermesTask) + it.dependsOn(bundleTask, hermesTask) // this was exposed before, do we still need it? - task.extra["generatedResFolders"] = files(resourcesDir).builtBy(task) - task.extra["generatedAssetsFolders"] = files(jsBundleDir).builtBy(task) + it.extensions.extraProperties["generatedResFolders"] = files(resourcesDir).builtBy(it) + it.extensions.extraProperties["generatedAssetsFolders"] = files(jsBundleDir).builtBy(it) } val generatedResFolders = files(resourcesDir).builtBy(aggregatedBundleTask) @@ -140,16 +136,16 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE val resourcesDirConfigValue = config.resourcesDir[variant.name] if (resourcesDirConfigValue != null) { val currentCopyResTask = - tasks.register("copy${targetName}BundledResources") { - group = "react" - description = "copy bundled resources into custom location for $targetName." + tasks.register("copy${targetName}BundledResources", Copy::class.java) { + it.group = "react" + it.description = "copy bundled resources into custom location for $targetName." - from(resourcesDir) - into(file(resourcesDirConfigValue)) + it.from(resourcesDir) + it.into(file(resourcesDirConfigValue)) - dependsOn(bundleTask) + it.dependsOn(bundleTask) - enabled = bundleEnabled + it.enabled = bundleEnabled } packageTask.dependsOn(currentCopyResTask) @@ -158,27 +154,27 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE packageTask.configure { if (config.enableVmCleanup) { - doFirst { cleanupVMFiles(enableHermes, isRelease, targetPath) } + it.doFirst { cleanupVMFiles(enableHermes, isRelease, targetPath) } } } val currentAssetsCopyTask = - tasks.register("copy${targetName}BundledJs") { - group = "react" - description = "copy bundled JS into $targetName." + tasks.register("copy${targetName}BundledJs", Copy::class.java) { + it.group = "react" + it.description = "copy bundled JS into $targetName." - from(jsBundleDir) + it.from(jsBundleDir) val jsBundleDirConfigValue = config.jsBundleDir[targetName] if (jsBundleDirConfigValue != null) { - into(jsBundleDirConfigValue) + it.into(jsBundleDirConfigValue) } else { - into(mergeAssetsTask.map { it.outputDir.get() }) + it.into(mergeAssetsTask.map { mergeFoldersTask -> mergeFoldersTask.outputDir.get() }) } - dependsOn(mergeAssetsTask) + it.dependsOn(mergeAssetsTask) - enabled = bundleEnabled + it.enabled = bundleEnabled } // mergeResources task runs before the bundle file is copied to the intermediate asset directory @@ -200,27 +196,27 @@ private fun Project.cleanupVMFiles(enableHermes: Boolean, isRelease: Boolean, ta fileTree(libDir) { if (enableHermes) { // For Hermes, delete all the libjsc* files - include("**/libjsc*.so") + it.include("**/libjsc*.so") if (isRelease) { // Reduce size by deleting the debugger/inspector - include("**/libhermes-inspector.so") - include("**/libhermes-executor-debug.so") + it.include("**/libhermes-inspector.so") + it.include("**/libhermes-executor-debug.so") } else { // Release libs take precedence and must be removed // to allow debugging - include("**/libhermes-executor-release.so") + it.include("**/libhermes-executor-release.so") } } else { // For JSC, delete all the libhermes* files - include("**/libhermes*.so") + it.include("**/libhermes*.so") } } - .visit { + .visit { visit -> val targetVariant = ".*/transforms/[^/]*/$targetPath/.*".toRegex() - val path = file.absolutePath.replace(File.separatorChar, '/') - if (path.matches(targetVariant) && file.isFile()) { - file.delete() + val path = visit.file.absolutePath.replace(File.separatorChar, '/') + if (path.matches(targetVariant) && visit.file.isFile) { + visit.file.delete() } } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleJsAndAssetsTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleJsAndAssetsTask.kt index 300774a48a0cb2..d5f10172767f66 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleJsAndAssetsTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleJsAndAssetsTask.kt @@ -53,10 +53,10 @@ open class BundleJsAndAssetsTask : DefaultTask() { private fun executeBundleCommand() { project.exec { - workingDir(reactRoot) + it.workingDir(reactRoot) @Suppress("SpreadOperator") - windowsAwareCommandLine( + it.windowsAwareCommandLine( *execCommand.toTypedArray(), bundleCommand, "--platform", diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/HermesBinaryTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/HermesBinaryTask.kt index af3ae0fe5ebd24..9a410462dde643 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/HermesBinaryTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/HermesBinaryTask.kt @@ -45,7 +45,7 @@ open class HermesBinaryTask : DefaultTask() { private fun emitHermesBinary(outputFile: File) { project.exec { @Suppress("SpreadOperator") - windowsAwareCommandLine( + it.windowsAwareCommandLine( hermesCommand, "-emit-binary", "-out", @@ -57,10 +57,10 @@ open class HermesBinaryTask : DefaultTask() { private fun composeSourceMaps() { project.exec { - workingDir(reactRoot) + it.workingDir(reactRoot) @Suppress("SpreadOperator") - windowsAwareCommandLine( + it.windowsAwareCommandLine( *composeSourceMapsCommand.toTypedArray(), jsPackagerSourceMapFile, jsCompilerSourceMapFile, diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 9fb2a10be87c70..265d84a18552fd 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -738,6 +738,7 @@ DEPENDENCIES: - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.99.0) - FlipperKit/SKIOSNetworkPlugin (= 0.99.0) - glog (from `../../third-party-podspecs/glog.podspec`) + - OpenSSL-Universal (= 1.1.180) - RCT-Folly (from `../../third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../../third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../../Libraries/RCTRequired`) @@ -918,6 +919,6 @@ SPEC CHECKSUMS: Yoga: c0d06f5380d34e939f55420669a60fe08b79bd75 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: ae3037f2256663bd77e3b1cffcac23908027fdb1 +PODFILE CHECKSUM: 5cc47caddf8a8bf3fe9ea873886352846aee027a COCOAPODS: 1.10.1 diff --git a/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m b/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m index a6d374f935a2c7..336168197f1c8d 100644 --- a/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m +++ b/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m @@ -48,9 +48,9 @@ - (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - [rootView.bridge.eventDispatcher sendAppEventWithName:@"rootViewDidChangeIntrinsicSize" - body:@{@"width": @(rootView.intrinsicSize.width), - @"height": @(rootView.intrinsicSize.height)}]; + [rootView.eventDispatcher sendAppEventWithName:@"rootViewDidChangeIntrinsicSize" + body:@{@"width": @(rootView.intrinsicSize.width), + @"height": @(rootView.intrinsicSize.height)}]; #pragma clang diagnostic pop } diff --git a/repo-config/package.json b/repo-config/package.json index bc6712214e06f1..c09bf529a56b41 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -36,7 +36,7 @@ "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-native": "3.10.0", "eslint-plugin-relay": "1.8.1", - "flow-bin": "^0.158.0", + "flow-bin": "^0.159.0", "jest": "^26.6.3", "jest-junit": "^10.0.0", "jscodeshift": "^0.11.0", diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 2325ad33c57437..0853df7e45bff1 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -65,7 +65,7 @@ def use_react_native! (options={}) if hermes_enabled pod 'React-hermes', :path => "#{prefix}/ReactCommon/hermes" - pod 'hermes-engine' + pod 'hermes-engine', '~> 0.9.0' pod 'libevent', '~> 2.1.12' end end @@ -79,6 +79,7 @@ def use_flipper!(versions = {}, configurations: ['Debug']) versions['Flipper-Glog'] ||= '0.3.6' versions['Flipper-PeerTalk'] ||= '0.0.4' versions['Flipper-RSocket'] ||= '1.4.3' + versions['OpenSSL-Universal'] ||= '1.1.180' pod 'FlipperKit', versions['Flipper'], :configurations => configurations pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configurations => configurations pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configurations => configurations @@ -102,6 +103,7 @@ def use_flipper!(versions = {}, configurations: ['Debug']) pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configurations => configurations pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configurations => configurations pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configurations => configurations + pod 'OpenSSL-Universal', versions['OpenSSL-Universal'], :configurations => configurations end def has_pod(installer, name) diff --git a/template/_flowconfig b/template/_flowconfig index 4320b7070ea698..cb5247b72a8257 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -62,4 +62,4 @@ untyped-import untyped-type-import [version] -^0.158.0 +^0.159.0 diff --git a/template/android/gradle/wrapper/gradle-wrapper.properties b/template/android/gradle/wrapper/gradle-wrapper.properties index 29e41345763549..af7be50b1015cb 100644 --- a/template/android/gradle/wrapper/gradle-wrapper.properties +++ b/template/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/template/android/gradlew.bat b/template/android/gradlew.bat deleted file mode 100644 index ac1b06f93825db..00000000000000 --- a/template/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/yarn.lock b/yarn.lock index c19efec0b0bed0..4b09b9772c6174 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3028,10 +3028,10 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flow-bin@^0.158.0: - version "0.158.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.158.0.tgz#0a09763d41eb8ec7135ced6a3b9f8fa370a393d8" - integrity sha512-Gk5md8XTwk/M+J5M+rFyS1LJfFen6ldY60jM9+meWixlKf4b0vwdoUO8R7oo471pze+GY+blrnskUeqLDxFJfg== +flow-bin@^0.159.0: + version "0.159.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.159.0.tgz#f788480d54db6da021e3440648c1dbb5dbc8aee8" + integrity sha512-5SugX7mOdfruzn2/+42DF74bxJO2SGmSEzCvTH9wOoBi98Ie87D5Hmb9OoGfwAE5SnXJmB6OCwN2WDiJe4lI+w== flow-parser@0.*, flow-parser@^0.121.0: version "0.121.0" @@ -3296,11 +3296,11 @@ has@^1.0.3: integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" - -hermes-engine@~0.8.0: - version "0.8.1" - resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.8.1.tgz#b6d0d70508ac5add2d198304502fb968cdecb8b2" - integrity sha512-as9Iccj/qrqqtDmfYUHbOIjt5xsQbUB6pjNIW3i1+RVr+pCAdz5S8/Jry778mz3rJWplYzHWdR1u1xQSYfBRYw== + +hermes-engine@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.9.0.tgz#84d9cfe84e8f6b1b2020d6e71b350cec84ed982f" + integrity sha512-r7U+Y4P2Qg/igFVZN+DpT7JFfXUn1MM4dFne8aW+cCrF6RRymof+VqrUHs1kl07j8h8V2CNesU19RKgWbr3qPw== hermes-parser@0.4.7: version "0.4.7"