Files
react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm
T
Paige Sun 743d0706e2 1/3 Add validation reporting APIs for unexpected uses of Paper when Fabric is enabled, in Bridge mode
Summary:
Changelog: [Internal][iOS] Add validation reporting APIs for unexpected uses of Paper when Fabric is enabled

## RCTNotAllowedInBridgeless
Previously, we only had violation reporting APIs for when **Bridge APIs** are used in **Bridgeless mode**, which was only enabled in Bridgeless mode.

## RCTNotAllowedInFabric
This diff adds violation reporting APIs to use when **pre-Fabric Bridge APIs** are used in **Bridge or Bridgeless mode**. This allows us to add RCTAssert/RCTError/RCTLog to more APIs in Bridge mode. The main purpose is to distinguish between Bridge APIs that still work in Fabric, versus Bridge APIs that are no longer used in Fabric, so that the latter can be removed.

Reviewed By: philIip

Differential Revision: D35015758

fbshipit-source-id: 35366bc5143a59ee9a16d75da4de546ebfe250e6
2022-03-22 20:14:32 -07:00

241 lines
8.0 KiB
Plaintext

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTLegacyViewManagerInteropComponentView.h"
#import <React/RCTAssert.h>
#import <React/RCTConstants.h>
#import <React/UIView+React.h>
#import <react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.h>
#import <react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropViewProps.h>
#import <react/utils/ManagedObjectWrapper.h>
#import "RCTLegacyViewManagerInteropCoordinatorAdapter.h"
using namespace facebook::react;
static NSString *const kRCTLegacyInteropChildComponentKey = @"childComponentView";
static NSString *const kRCTLegacyInteropChildIndexKey = @"index";
@implementation RCTLegacyViewManagerInteropComponentView {
NSMutableArray<NSDictionary *> *_viewsToBeMounted;
NSMutableArray<UIView *> *_viewsToBeUnmounted;
RCTLegacyViewManagerInteropCoordinatorAdapter *_adapter;
LegacyViewManagerInteropShadowNode::ConcreteState::Shared _state;
BOOL _hasInvokedForwardingWarning;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const LegacyViewManagerInteropViewProps>();
_props = defaultProps;
_viewsToBeMounted = [NSMutableArray new];
_viewsToBeUnmounted = [NSMutableArray new];
_hasInvokedForwardingWarning = NO;
}
return self;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *result = [super hitTest:point withEvent:event];
if (result == _adapter.paperView) {
return self;
}
return result;
}
- (RCTLegacyViewManagerInteropCoordinator *)_coordinator
{
if (_state != nullptr) {
const auto &state = _state->getData();
return unwrapManagedObject(state.coordinator);
} else {
return nil;
}
}
- (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN
{
const auto &state = _state->getData();
RCTLegacyViewManagerInteropCoordinator *coordinator = unwrapManagedObject(state.coordinator);
return coordinator.componentViewName;
}
#pragma mark - Method forwarding
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if (!_hasInvokedForwardingWarning) {
_hasInvokedForwardingWarning = YES;
NSLog(
@"Invoked unsupported method on RCTLegacyViewManagerInteropComponentView. Resulting to noop instead of a crash.");
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [super methodSignatureForSelector:aSelector] ?: [self.contentView methodSignatureForSelector:aSelector];
}
#pragma mark - Supported ViewManagers
+ (NSMutableSet<NSString *> *)supportedViewManagers
{
static NSMutableSet<NSString *> *supported = [NSMutableSet setWithObjects:@"DatePicker",
@"ProgressView",
@"SegmentedControl",
@"MaskedView",
@"ARTSurfaceView",
@"ARTText",
@"ARTShape",
@"ARTGroup",
nil];
return supported;
}
+ (NSMutableSet<NSString *> *)supportedViewManagersPrefixes
{
static NSMutableSet<NSString *> *supported = [NSMutableSet new];
return supported;
}
+ (BOOL)isSupported:(NSString *)componentName
{
RCTLogNewArchitectureValidation(
RCTNotAllowedInBridgeless,
self,
[NSString
stringWithFormat:
@"Legacy ViewManagers should be migrated to Fabric ComponentViews in the new architecture to reduce risk. Component using interop layer: %@",
componentName]);
// Step 1: check if ViewManager with specified name is supported.
BOOL isComponentNameSupported =
[[RCTLegacyViewManagerInteropComponentView supportedViewManagers] containsObject:componentName];
if (isComponentNameSupported) {
return YES;
}
// Step 2: check if component has supported prefix.
for (NSString *item in [RCTLegacyViewManagerInteropComponentView supportedViewManagersPrefixes]) {
if ([componentName hasPrefix:item]) {
return YES;
}
}
return NO;
}
+ (void)supportLegacyViewManagersWithPrefix:(NSString *)prefix
{
[[RCTLegacyViewManagerInteropComponentView supportedViewManagersPrefixes] addObject:prefix];
}
+ (void)supportLegacyViewManagerWithName:(NSString *)componentName
{
[[RCTLegacyViewManagerInteropComponentView supportedViewManagers] addObject:componentName];
}
#pragma mark - RCTComponentViewProtocol
- (void)prepareForRecycle
{
_adapter = nil;
[_viewsToBeMounted removeAllObjects];
[_viewsToBeUnmounted removeAllObjects];
_state.reset();
self.contentView = nil;
_hasInvokedForwardingWarning = NO;
[super prepareForRecycle];
}
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[_viewsToBeMounted addObject:@{
kRCTLegacyInteropChildIndexKey : [NSNumber numberWithInteger:index],
kRCTLegacyInteropChildComponentKey : childComponentView
}];
}
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
if (_adapter) {
[_adapter.paperView removeReactSubview:childComponentView];
} else {
[_viewsToBeUnmounted addObject:childComponentView];
}
}
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<LegacyViewManagerInteropComponentDescriptor>();
}
- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState
{
_state = std::static_pointer_cast<LegacyViewManagerInteropShadowNode::ConcreteState const>(state);
}
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
{
[super finalizeUpdates:updateMask];
if (!_adapter) {
_adapter = [[RCTLegacyViewManagerInteropCoordinatorAdapter alloc] initWithCoordinator:[self _coordinator]
reactTag:self.tag];
__weak __typeof(self) weakSelf = self;
_adapter.eventInterceptor = ^(std::string eventName, folly::dynamic event) {
if (weakSelf) {
__typeof(self) strongSelf = weakSelf;
auto eventEmitter =
std::static_pointer_cast<LegacyViewManagerInteropViewEventEmitter const>(strongSelf->_eventEmitter);
eventEmitter->dispatchEvent(eventName, event);
}
};
self.contentView = _adapter.paperView;
}
for (NSDictionary *mountInstruction in _viewsToBeMounted) {
NSNumber *index = mountInstruction[kRCTLegacyInteropChildIndexKey];
UIView *childView = mountInstruction[kRCTLegacyInteropChildComponentKey];
if ([childView isKindOfClass:[RCTLegacyViewManagerInteropComponentView class]]) {
UIView *target = ((RCTLegacyViewManagerInteropComponentView *)childView).contentView;
[_adapter.paperView insertReactSubview:target atIndex:index.integerValue];
} else {
[_adapter.paperView insertReactSubview:childView atIndex:index.integerValue];
}
}
[_viewsToBeMounted removeAllObjects];
for (UIView *view in _viewsToBeUnmounted) {
[_adapter.paperView removeReactSubview:view];
}
[_viewsToBeUnmounted removeAllObjects];
[_adapter.paperView didUpdateReactSubviews];
if (updateMask & RNComponentViewUpdateMaskProps) {
const auto &newProps = *std::static_pointer_cast<const LegacyViewManagerInteropViewProps>(_props);
[_adapter setProps:newProps.otherProps];
}
}
#pragma mark - Native Commands
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
{
[_adapter handleCommand:(NSString *)commandName args:(NSArray *)args];
}
@end