Skip to content

use C++ Native Animated from JS if enabled #51337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
* @format
*/

import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
import Platform from '../Utilities/Platform';

function shouldUseTurboAnimatedModule(): boolean {
return Platform.OS === 'ios' && global.RN$Bridgeless === true;
if (ReactNativeFeatureFlags.cxxNativeAnimatedEnabled()) {
return false;
} else {
return Platform.OS === 'ios' && global.RN$Bridgeless === true;
}
}

export default shouldUseTurboAnimatedModule;
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import <React/RCTStyleAnimatedNode.h>
#import <React/RCTUIManager.h>
#import <React/RCTValueAnimatedNode.h>
#import <react/utils/FollyConvert.h>

@implementation RCTPropsAnimatedNode {
NSNumber *_connectedViewTag;
Expand Down Expand Up @@ -61,9 +62,12 @@ - (void)updateView
{
if (_managedByFabric) {
if (_bridge.surfacePresenter) {
[_bridge.surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag props:_propsDictionary];
[_bridge.surfacePresenter
synchronouslyUpdateViewOnUIThread:_connectedViewTag.integerValue
props:facebook::react::convertIdToFollyDynamic(_propsDictionary)];
} else {
[_surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag props:_propsDictionary];
[_surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag.integerValue
props:facebook::react::convertIdToFollyDynamic(_propsDictionary)];
}
} else {
[_bridge.uiManager synchronouslyUpdateViewOnUIThread:_connectedViewTag
Expand Down
1 change: 0 additions & 1 deletion packages/react-native/React/Base/RCTViewRegistry.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/

#import <React/RCTSurfacePresenterStub.h>
#import <React/RCTUIManager.h>

#import "RCTBridge.h"
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native/React/CxxUtils/RCTFollyConvert.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace facebook::react {
folly::dynamic convertIdToFollyDynamic(id json);
[[deprecated(
"This function is deprecated, please use /ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h instead")]]
id convertFollyDynamicToId(const folly::dynamic& dyn);
id convertFollyDynamicToId(const folly::dynamic &dyn);
NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn);

} // namespace facebook::react
16 changes: 16 additions & 0 deletions packages/react-native/React/CxxUtils/RCTFollyConvert.mm
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,20 @@ id convertFollyDynamicToId(const folly::dynamic &dyn)
return nil;
}

NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn)
{
NSMutableArray<NSString *> *result = [NSMutableArray new];

if (dyn.type() == folly::dynamic::OBJECT) {
for (const auto &elem : dyn.items()) {
NSString *key = [[NSString alloc] initWithBytes:elem.first.c_str()
length:elem.first.size()
encoding:NSUTF8StringEncoding];
[result addObject:key];
}
}

return result;
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
forShadowView:(const facebook::react::ShadowView &)shadowView;

- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
changedProps:(NSDictionary *)props
changedProps:(folly::dynamic)props
componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor;
@end

Expand Down
19 changes: 14 additions & 5 deletions packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -282,25 +282,34 @@ - (void)setIsJSResponder:(BOOL)isJSResponder
}

- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
changedProps:(NSDictionary *)props
changedProps:(folly::dynamic)props
componentDescriptor:(const ComponentDescriptor &)componentDescriptor
{
RCTAssertMainQueue();
NSArray<NSString *> *propsKeysToBeUpdated = extractKeysFromFollyDynamic(props);
bool updatesTransform = props.find("transform") != props.items().end();
bool updatesOpacity = props.find("opacity") != props.items().end();

UIView<RCTComponentViewProtocol> *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag];
if (!componentView) {
RCTLogWarn(@"Attempted to update view with tag %ld, but it no longer exists", (long)reactTag);
return;
}

SurfaceId surfaceId = RCTSurfaceIdForView(componentView);
Props::Shared oldProps = [componentView props];
Props::Shared newProps = componentDescriptor.cloneProps(
PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(convertIdToFollyDynamic(props)));
PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(std::move(props)));

NSSet<NSString *> *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new];
propKeys = [propKeys setByAddingObjectsFromArray:props.allKeys];
propKeys = [propKeys setByAddingObjectsFromArray:propsKeysToBeUpdated];
componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = nil;
[componentView updateProps:newProps oldProps:oldProps];
componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = propKeys;

const auto &newViewProps = static_cast<const ViewProps &>(*newProps);

if (props[@"transform"]) {
if (updatesTransform) {
auto layoutMetrics = LayoutMetrics();
layoutMetrics.frame.size.width = componentView.layer.bounds.size.width;
layoutMetrics.frame.size.height = componentView.layer.bounds.size.height;
Expand All @@ -309,7 +318,7 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
componentView.layer.transform = newTransform;
}
}
if (props[@"opacity"] && componentView.layer.opacity != (float)newViewProps.opacity) {
if (updatesOpacity && componentView.layer.opacity != (float)newViewProps.opacity) {
componentView.layer.opacity = newViewProps.opacity;
}

Expand Down
1 change: 1 addition & 0 deletions packages/react-native/React/Fabric/RCTScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
blockNativeResponder:(BOOL)blockNativeResponder
forShadowView:(const facebook::react::ShadowView &)shadowView;

- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(facebook::react::Tag)reactTag props:(folly::dynamic)props;
@end

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/react-native/React/Fabric/RCTScheduler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ void schedulerDidSendAccessibilityEvent(const ShadowView &shadowView, const std:

void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic &props) override
{
// Does nothing.
// This delegate method is not currently used on iOS.
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
[scheduler.delegate schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:props];
}

private:
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native/React/Fabric/RCTSurfacePresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ NS_ASSUME_NONNULL_BEGIN

- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;

- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag props:(folly::dynamic)props;
- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)reactTag props:(folly::dynamic)props;

- (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler;

Expand Down
22 changes: 13 additions & 9 deletions packages/react-native/React/Fabric/RCTSurfacePresenter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -148,28 +148,32 @@ - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag
return componentView;
}

- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props
- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)reactTag props:(folly::dynamic)props
{
[self synchronouslyUpdateViewOnUIThread:reactTag props:std::move(props)];
}

- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag props:(folly::dynamic)props
{
RCTScheduler *scheduler = [self scheduler];
if (!scheduler) {
return NO;
return;
}

ReactTag tag = [reactTag integerValue];
UIView<RCTComponentViewProtocol> *componentView =
[_mountingManager.componentViewRegistry findComponentViewWithTag:tag];
[_mountingManager.componentViewRegistry findComponentViewWithTag:reactTag];
if (componentView == nil) {
return NO; // This view probably isn't managed by Fabric
return; // This view probably isn't managed by Fabric
}
ComponentHandle handle = [[componentView class] componentDescriptorProvider].handle;
auto *componentDescriptor = [scheduler findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN:handle];

if (!componentDescriptor) {
return YES;
return;
}

[_mountingManager synchronouslyUpdateViewOnUIThread:tag changedProps:props componentDescriptor:*componentDescriptor];
return YES;
[_mountingManager synchronouslyUpdateViewOnUIThread:reactTag
changedProps:std::move(props)
componentDescriptor:*componentDescriptor];
}

- (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#import <React/RCTBridge.h>
#import <React/RCTBridgeProxy.h>
#import <folly/dynamic.h>

@protocol RCTSurfaceProtocol;

Expand All @@ -32,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
- (id<RCTSurfaceProtocol>)createFabricSurfaceForModuleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties;
- (nullable UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag;
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
- (void)synchronouslyUpdateViewOnUIThread:(NSInteger)reactTag props:(folly::dynamic)props;
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer;
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace facebook::react {

folly::dynamic convertIdToFollyDynamic(id json);
id convertFollyDynamicToId(const folly::dynamic& dyn);
id convertFollyDynamicToId(const folly::dynamic &dyn);
NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn);

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,20 @@ id convertFollyDynamicToId(const folly::dynamic &dyn)
return nil;
}

NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn)
{
NSMutableArray<NSString *> *result = [NSMutableArray new];

if (dyn.type() == folly::dynamic::OBJECT) {
for (const auto &elem : dyn.items()) {
NSString *key = [[NSString alloc] initWithBytes:elem.first.c_str()
length:elem.first.size()
encoding:NSUTF8StringEncoding];
[result addObject:key];
}
}

return result;
}

} // namespace facebook::react
Loading