11#import " RNNBottomTabsController.h"
22#import " UITabBar+utils.h"
33#import " UITabBarController+RNNOptions.h"
4+ #import < objc/runtime.h>
5+
6+ static const NSTimeInterval RNNTabBarTestIDRetryDelay = 0.15 ;
7+ static const NSUInteger RNNTabBarTestIDMaxRetryAttempts = 5 ;
8+ static const void *RNNTabBarTestIDRetryScheduledKey = &RNNTabBarTestIDRetryScheduledKey;
9+ static const void *RNNTabBarTestIDRetryAttemptsKey = &RNNTabBarTestIDRetryAttemptsKey;
10+ static const void *RNNOriginalTabBarViewAccessibilityIdentifierKey =
11+ &RNNOriginalTabBarViewAccessibilityIdentifierKey;
412
513@implementation UITabBarController (RNNOptions)
614
15+ - (void )rnn_storeOriginalAccessibilityIdentifierIfNeededForTabView : (UIView *)tabView {
16+ if (objc_getAssociatedObject (tabView, RNNOriginalTabBarViewAccessibilityIdentifierKey))
17+ return ;
18+
19+ id originalAccessibilityIdentifier = tabView.accessibilityIdentifier ?: [NSNull null ];
20+ objc_setAssociatedObject (tabView, RNNOriginalTabBarViewAccessibilityIdentifierKey,
21+ originalAccessibilityIdentifier,
22+ OBJC_ASSOCIATION_RETAIN_NONATOMIC );
23+ }
24+
25+ - (void )rnn_applyTestID : (NSString *)testID toTabView : (UIView *)tabView {
26+ [self rnn_storeOriginalAccessibilityIdentifierIfNeededForTabView: tabView];
27+ tabView.accessibilityIdentifier = testID;
28+ }
29+
30+ - (void )rnn_restoreOriginalAccessibilityIdentifierForTabView : (UIView *)tabView {
31+ id originalAccessibilityIdentifier =
32+ objc_getAssociatedObject (tabView, RNNOriginalTabBarViewAccessibilityIdentifierKey);
33+ if (!originalAccessibilityIdentifier)
34+ return ;
35+
36+ tabView.accessibilityIdentifier =
37+ [originalAccessibilityIdentifier isKindOfClass: NSNull .class ]
38+ ? nil
39+ : originalAccessibilityIdentifier;
40+ objc_setAssociatedObject (tabView, RNNOriginalTabBarViewAccessibilityIdentifierKey, nil ,
41+ OBJC_ASSOCIATION_RETAIN_NONATOMIC );
42+ }
43+
44+ - (BOOL )rnn_isTabBarTestIDRetryScheduled {
45+ return [objc_getAssociatedObject (self , RNNTabBarTestIDRetryScheduledKey) boolValue ];
46+ }
47+
48+ - (void )rnn_setTabBarTestIDRetryScheduled : (BOOL )scheduled {
49+ objc_setAssociatedObject (self, RNNTabBarTestIDRetryScheduledKey, @(scheduled),
50+ OBJC_ASSOCIATION_RETAIN_NONATOMIC );
51+ }
52+
53+ - (NSUInteger )rnn_tabBarTestIDRetryAttempts {
54+ NSNumber *retryAttempts = objc_getAssociatedObject (self, RNNTabBarTestIDRetryAttemptsKey);
55+ return retryAttempts.unsignedIntegerValue ;
56+ }
57+
58+ - (void )rnn_setTabBarTestIDRetryAttempts : (NSUInteger )retryAttempts {
59+ objc_setAssociatedObject (self, RNNTabBarTestIDRetryAttemptsKey, @(retryAttempts),
60+ OBJC_ASSOCIATION_RETAIN_NONATOMIC );
61+ }
62+
63+ - (BOOL )rnn_applyTabBarItemTestIDs {
64+ NSArray <UITabBarItem *> *items = self.tabBar .items ?: @[];
65+ BOOL appliedAllKnownTestIDs = YES ;
66+
67+ for (NSUInteger tabIndex = 0 ; tabIndex < items.count ; tabIndex++) {
68+ UITabBarItem *item = items[tabIndex];
69+ NSString *testID = item.accessibilityIdentifier ;
70+ UIView *tabView = [self .tabBar tabBarItemViewAtIndex: tabIndex];
71+ if (testID.length > 0 && tabView) {
72+ [self rnn_applyTestID: testID toTabView: tabView];
73+ } else if (tabView) {
74+ [self rnn_restoreOriginalAccessibilityIdentifierForTabView: tabView];
75+ } else if (testID.length > 0 ) {
76+ appliedAllKnownTestIDs = NO ;
77+ }
78+ }
79+
80+ return appliedAllKnownTestIDs;
81+ }
82+
783- (void )setCurrentTabIndex : (NSUInteger )currentTabIndex {
884 [self setSelectedIndex: currentTabIndex];
985}
@@ -16,6 +92,38 @@ - (void)setTabBarTestID:(NSString *)testID {
1692 self.tabBar .accessibilityIdentifier = testID;
1793}
1894
95+ - (void )syncTabBarItemTestIDs {
96+ if ([self rnn_applyTabBarItemTestIDs ]) {
97+ [self rnn_setTabBarTestIDRetryScheduled: NO ];
98+ [self rnn_setTabBarTestIDRetryAttempts: 0 ];
99+ return ;
100+ }
101+
102+ if ([self rnn_isTabBarTestIDRetryScheduled ])
103+ return ;
104+
105+ NSUInteger retryAttempts = [self rnn_tabBarTestIDRetryAttempts ];
106+ if (retryAttempts >= RNNTabBarTestIDMaxRetryAttempts) {
107+ [self rnn_setTabBarTestIDRetryAttempts: 0 ];
108+ return ;
109+ }
110+
111+ [self rnn_setTabBarTestIDRetryScheduled: YES ];
112+ [self rnn_setTabBarTestIDRetryAttempts: retryAttempts + 1 ];
113+
114+ __weak UITabBarController *weakSelf = self;
115+ dispatch_after (dispatch_time (DISPATCH_TIME_NOW,
116+ (int64_t )(RNNTabBarTestIDRetryDelay * NSEC_PER_SEC)),
117+ dispatch_get_main_queue (), ^{
118+ UITabBarController *controller = weakSelf;
119+ if (!controller)
120+ return ;
121+
122+ [controller rnn_setTabBarTestIDRetryScheduled: NO ];
123+ [controller syncTabBarItemTestIDs ];
124+ });
125+ }
126+
19127- (void )setTabBarStyle : (UIBarStyle)barStyle {
20128 self.tabBar .barStyle = barStyle;
21129}
0 commit comments