diff --git a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Serializers/UIDInitEvent+Foundation.m b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Serializers/UIDInitEvent+Foundation.m index 9b6eb5065..89a2c1b27 100644 --- a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Serializers/UIDInitEvent+Foundation.m +++ b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Serializers/UIDInitEvent+Foundation.m @@ -8,6 +8,7 @@ #if FB_SONARKIT_ENABLED #import "NSArray+Foundation.h" +#import "UIDAllyTraversal.h" #import "UIDInitEvent+Foundation.h" #import "UIDTraversalMode.h" @@ -20,12 +21,15 @@ FB_LINKABLE(UIDInitEvent_Foundation) @"frameworkEventMetadata" : self.frameworkEventMetadata ? [self.frameworkEventMetadata toFoundation] : @[], - @"supportedTraversalModes" : @[ + @"supportedTraversalModes" : UIDAllyTraversal.isSupported ? @[ NSStringFromUIDTraversalMode(UIDTraversalModeViewHierarchy), NSStringFromUIDTraversalMode(UIDTraversalModeAccessibilityHierarchy), + ] : @[ + NSStringFromUIDTraversalMode(UIDTraversalModeViewHierarchy), ], - @"currentTraversalMode" : - NSStringFromUIDTraversalMode(self.currentTraversalMode), + @"currentTraversalMode" : NSStringFromUIDTraversalMode( + UIDAllyTraversal.isSupported ? self.currentTraversalMode + : UIDTraversalModeViewHierarchy), }; } diff --git a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.h b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.h index 95c17a457..4f97a2e79 100644 --- a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.h +++ b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.h @@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN @interface UIDAllyTraversal : NSObject +@property(nonatomic, class, readonly, getter=isSupported) BOOL supported; + - (instancetype)initWithDescriptorRegister: (UIDDescriptorRegister*)descriptorRegister; diff --git a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.m b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.m index 040a8e98b..7e0ed379d 100644 --- a/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.m +++ b/iOS/Plugins/FlipperKitUIDebuggerPlugin/FlipperKitUIDebuggerPlugin/Traversal/UIDAllyTraversal.m @@ -27,6 +27,13 @@ UIDDescriptorRegister* _descriptorRegister; } ++ (BOOL)isSupported { + return _loadAccessibilityFramework() && + [UIApplication.sharedApplication + respondsToSelector:@selector + (_accessibilityLeafDescendantsWithOptions:)]; +} + - (instancetype)initWithDescriptorRegister: (UIDDescriptorRegister*)descriptorRegister { self = [super init]; @@ -41,10 +48,18 @@ return @[]; } + if (!_loadAccessibilityFramework()) { + return @[]; + } + // create voice over representation of the app id options = [NSClassFromString(@"UIAccessibilityElementTraversalOptions") voiceOverOptionsIncludingElementsFromOpaqueProviders:YES honorsGroups:NO]; + if (![application respondsToSelector:@selector + (_accessibilityLeafDescendantsWithOptions:)]) { + return @[]; + } NSArray* const allyNodes = [[application _accessibilityLeafDescendantsWithOptions:options] mutableCopy]; @@ -78,6 +93,27 @@ return uidNode; } +static BOOL _loadAccessibilityFramework(void) { + static BOOL isAccessibilityFrameworkLoaded; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSURL* const knownFrameworkUrl = + [NSBundle bundleForClass:UIApplication.class].bundleURL; + if (!knownFrameworkUrl) { + isAccessibilityFrameworkLoaded = NO; + } else { + NSURL* const accessibilityFrameworkUrl = + [knownFrameworkUrl.URLByDeletingLastPathComponent + .URLByDeletingLastPathComponent + URLByAppendingPathComponent: + @"PrivateFrameworks/UIAccessibility.framework"]; + isAccessibilityFrameworkLoaded = + [[NSBundle bundleWithURL:accessibilityFrameworkUrl] load]; + } + }); + return isAccessibilityFrameworkLoaded; +} + static NSString* _nameForNode(NSObject* node) { NSMutableArray* const parts = [NSMutableArray new]; if (node.accessibilityLabel.length > 0) {