mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
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
241 lines
8.0 KiB
Plaintext
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
|