appium-webdriveragent 16.1.7 → 16.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/Scripts/embed-runner-icon.sh +49 -18
  3. package/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.m +1 -1
  4. package/WebDriverAgentLib/Categories/XCUIApplicationProcess+FBQuiescence.m +4 -4
  5. package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +1 -1
  6. package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +1 -1
  7. package/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +1 -1
  8. package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +1 -1
  9. package/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m +1 -1
  10. package/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +5 -5
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +4 -4
  12. package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +1 -1
  13. package/WebDriverAgentLib/Commands/FBElementCommands.m +3 -3
  14. package/WebDriverAgentLib/Commands/FBFindElementCommands.m +7 -7
  15. package/WebDriverAgentLib/Commands/FBSessionCommands.m +10 -10
  16. package/WebDriverAgentLib/FBAlert.m +7 -7
  17. package/WebDriverAgentLib/Info.plist +2 -2
  18. package/WebDriverAgentLib/Routing/FBResponsePayload.m +1 -1
  19. package/WebDriverAgentLib/Routing/FBSession.m +3 -3
  20. package/WebDriverAgentLib/Routing/FBWebServer.m +7 -7
  21. package/WebDriverAgentLib/Utilities/FBConfiguration.h +75 -142
  22. package/WebDriverAgentLib/Utilities/FBConfiguration.m +128 -374
  23. package/WebDriverAgentLib/Utilities/FBImageProcessor.m +6 -6
  24. package/WebDriverAgentLib/Utilities/FBLogger.m +2 -2
  25. package/WebDriverAgentLib/Utilities/FBMjpegServer.m +4 -4
  26. package/WebDriverAgentLib/Utilities/FBSettingsHandler.m +65 -61
  27. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +1 -1
  28. package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.m +1 -1
  29. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +2 -2
  30. package/WebDriverAgentLib/Utilities/FBXPath.m +9 -9
  31. package/WebDriverAgentRunner/UITestingUITests.m +7 -7
  32. package/WebDriverAgentTests/IntegrationTests/FBAlertTests.m +5 -5
  33. package/WebDriverAgentTests/IntegrationTests/FBConfigurationTests.m +5 -5
  34. package/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m +6 -6
  35. package/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +3 -3
  36. package/WebDriverAgentTests/IntegrationTests/XCUIElementAttributesTests.m +5 -5
  37. package/WebDriverAgentTests/UnitTests/FBConfigurationTests.m +8 -8
  38. package/WebDriverAgentTests/UnitTests/FBSessionTests.m +3 -3
  39. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [16.2.1](https://github.com/appium/WebDriverAgent/compare/v16.2.0...v16.2.1) (2026-08-17)
2
+
3
+ ### Bug Fixes
4
+
5
+ * sign the runner by certificate hash instead of display name ([#1211](https://github.com/appium/WebDriverAgent/issues/1211)) ([59e95a7](https://github.com/appium/WebDriverAgent/commit/59e95a73986a91c90c951608d7744a032997810b))
6
+
7
+ ## [16.2.0](https://github.com/appium/WebDriverAgent/compare/v16.1.7...v16.2.0) (2026-08-13)
8
+
9
+ ### Features
10
+
11
+ * Convert FBConfiguration to a singleton with native properties ([#1208](https://github.com/appium/WebDriverAgent/issues/1208)) ([ee029da](https://github.com/appium/WebDriverAgent/commit/ee029da84448895c4ad51be0688e7b7df30697de))
12
+
1
13
  ## [16.1.7](https://github.com/appium/WebDriverAgent/compare/v16.1.6...v16.1.7) (2026-08-11)
2
14
 
3
15
  ### Bug Fixes
@@ -36,12 +36,32 @@ if [ ${#ICONS[@]} -eq 0 ]; then
36
36
  exit 0
37
37
  fi
38
38
 
39
- cp -f "${ICONS[@]}" "$RUNNER_APP/"
39
+ PLIST="$RUNNER_APP/Info.plist"
40
+
41
+ # Everything below mutates a bundle Xcode already signed, so keep enough state
42
+ # to undo it: a failed re-sign must not leave an uninstallable runner behind.
43
+ PLIST_BACKUP=$(mktemp)
44
+ CERT_DIR=$(mktemp -d)
45
+ trap 'rm -rf "$PLIST_BACKUP" "$CERT_DIR"' EXIT
46
+ cp "$PLIST" "$PLIST_BACKUP"
47
+ ADDED_FILES=()
48
+
49
+ restore_bundle() {
50
+ cp -f "$PLIST_BACKUP" "$PLIST"
51
+ if [ ${#ADDED_FILES[@]} -gt 0 ]; then
52
+ rm -f "${ADDED_FILES[@]}"
53
+ fi
54
+ }
55
+
56
+ for icon in "${ICONS[@]}"; do
57
+ dest="$RUNNER_APP/$(basename "$icon")"
58
+ [ -e "$dest" ] || ADDED_FILES+=("$dest")
59
+ cp -f "$icon" "$dest"
60
+ done
40
61
  if [ -f "$XCTEST/Assets.car" ]; then
62
+ [ -e "$RUNNER_APP/Assets.car" ] || ADDED_FILES+=("$RUNNER_APP/Assets.car")
41
63
  cp -f "$XCTEST/Assets.car" "$RUNNER_APP/"
42
64
  fi
43
-
44
- PLIST="$RUNNER_APP/Info.plist"
45
65
  /usr/libexec/PlistBuddy -c "Delete :CFBundleIcons" "$PLIST" 2>/dev/null || true
46
66
  /usr/libexec/PlistBuddy -c "Delete :CFBundleIcons~ipad" "$PLIST" 2>/dev/null || true
47
67
 
@@ -58,29 +78,40 @@ PLIST="$RUNNER_APP/Info.plist"
58
78
  /usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:0 string AppIcon60x60" "$PLIST"
59
79
  /usr/libexec/PlistBuddy -c "Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:1 string AppIcon76x76" "$PLIST"
60
80
 
61
- # Re-codesign since we modified the bundle after Xcode signed it.
62
- # In a scheme post-action context Xcode's CODE_SIGN_* env vars are not exposed,
63
- # so discover the existing signing identity from the already-signed bundle.
81
+ # Re-codesign since we modified the bundle after Xcode signed it. Scheme
82
+ # post-actions never receive EXPANDED_CODE_SIGN_IDENTITY, so the signer has to
83
+ # be recovered from the already-signed bundle.
64
84
  if [ -d "$RUNNER_APP/_CodeSignature" ]; then
65
85
  # Capture the signature info once. Piping codesign straight into
66
86
  # `awk ... exit` makes awk close the pipe early, killing codesign with
67
87
  # SIGPIPE -- which `set -o pipefail` turns into a fatal error. That trips
68
88
  # only when an Authority line exists, i.e. on every real-device build.
69
89
  SIGN_INFO=$(codesign -dvv "$RUNNER_APP" 2>&1 || true)
70
- EXISTING_IDENT="${EXPANDED_CODE_SIGN_IDENTITY:-}"
71
- if [ -z "$EXISTING_IDENT" ]; then
72
- EXISTING_IDENT=$(awk -F'=' '/^Authority/ {print $2; exit}' <<< "$SIGN_INFO")
73
- fi
74
- # Simulator builds are ad-hoc signed: there is no Authority line, but the
75
- # bundle can still be re-signed ad-hoc with an identity of "-".
76
- if [ -z "$EXISTING_IDENT" ] && grep -q '^Signature=adhoc' <<< "$SIGN_INFO"; then
90
+
91
+ if grep -q '^Signature=adhoc' <<< "$SIGN_INFO"; then
92
+ # Simulator builds are ad-hoc signed; re-sign them ad-hoc.
77
93
  EXISTING_IDENT="-"
78
- fi
79
- if [ -n "$EXISTING_IDENT" ]; then
80
- codesign --force --sign "$EXISTING_IDENT" \
81
- --preserve-metadata=identifier,entitlements "$RUNNER_APP"
82
94
  else
83
- echo "warning: bundle is signed but no identity discovered; signature will be invalid"
95
+ # Identify the signer by leaf-certificate SHA-1, never by Authority
96
+ # display name: duplicate identities can share a name, and codesign
97
+ # then rejects the name as ambiguous (Apple TN3161).
98
+ EXISTING_IDENT=""
99
+ if codesign -d --extract-certificates="$CERT_DIR/leaf" "$RUNNER_APP" 2>/dev/null \
100
+ && [ -f "$CERT_DIR/leaf0" ]; then
101
+ EXISTING_IDENT=$(shasum -a 1 "$CERT_DIR/leaf0" | awk '{print toupper($1)}')
102
+ fi
103
+ if [ -z "$EXISTING_IDENT" ]; then
104
+ EXISTING_IDENT=$(awk -F'=' '/^Authority/ {print $2; exit}' <<< "$SIGN_INFO")
105
+ fi
106
+ fi
107
+
108
+ if [ -z "$EXISTING_IDENT" ] || ! codesign --force --sign "$EXISTING_IDENT" \
109
+ --preserve-metadata=identifier,entitlements "$RUNNER_APP"; then
110
+ # A modified-but-stale-signed bundle fails to install, which would break
111
+ # the session over a cosmetic icon. Undo instead.
112
+ restore_bundle
113
+ echo "warning: could not re-sign $RUNNER_APP; skipped icon embed"
114
+ exit 0
84
115
  fi
85
116
  fi
86
117
 
@@ -61,7 +61,7 @@
61
61
  error:error]) {
62
62
  return NO;
63
63
  }
64
- [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
64
+ [self fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.animationCoolOffTimeout];
65
65
  return YES;
66
66
  }
67
67
 
@@ -22,13 +22,13 @@ static void (*original_waitForQuiescenceIncludingAnimationsIdlePreEvent)(id, SEL
22
22
  static void swizzledWaitForQuiescenceIncludingAnimationsIdle(id self, SEL _cmd, BOOL includingAnimations)
23
23
  {
24
24
  NSString *bundleId = [self bundleID];
25
- if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.waitForIdleTimeout < DBL_EPSILON) {
25
+ if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.sharedInstance.waitForIdleTimeout < DBL_EPSILON) {
26
26
  [FBLogger logFmt:@"Quiescence checks are disabled for %@ application. Making it to believe it is idling",
27
27
  bundleId];
28
28
  return;
29
29
  }
30
30
 
31
- NSTimeInterval desiredTimeout = FBConfiguration.waitForIdleTimeout;
31
+ NSTimeInterval desiredTimeout = FBConfiguration.sharedInstance.waitForIdleTimeout;
32
32
  NSTimeInterval previousTimeout = _XCTApplicationStateTimeout();
33
33
  _XCTSetApplicationStateTimeout(desiredTimeout);
34
34
  [FBLogger logFmt:@"Waiting up to %@s until %@ is in idle state (%@ animations)",
@@ -43,13 +43,13 @@ static void swizzledWaitForQuiescenceIncludingAnimationsIdle(id self, SEL _cmd,
43
43
  static void swizzledWaitForQuiescenceIncludingAnimationsIdlePreEvent(id self, SEL _cmd, BOOL includingAnimations, BOOL isPreEvent)
44
44
  {
45
45
  NSString *bundleId = [self bundleID];
46
- if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.waitForIdleTimeout < DBL_EPSILON) {
46
+ if (![[self fb_shouldWaitForQuiescence] boolValue] || FBConfiguration.sharedInstance.waitForIdleTimeout < DBL_EPSILON) {
47
47
  [FBLogger logFmt:@"Quiescence checks are disabled for %@ application. Making it to believe it is idling",
48
48
  bundleId];
49
49
  return;
50
50
  }
51
51
 
52
- NSTimeInterval desiredTimeout = FBConfiguration.waitForIdleTimeout;
52
+ NSTimeInterval desiredTimeout = FBConfiguration.sharedInstance.waitForIdleTimeout;
53
53
  NSTimeInterval previousTimeout = _XCTApplicationStateTimeout();
54
54
  _XCTSetApplicationStateTimeout(desiredTimeout);
55
55
  [FBLogger logFmt:@"Waiting up to %@s until %@ is in idle state (%@ animations)",
@@ -174,7 +174,7 @@ static bool fb_isLocked;
174
174
 
175
175
  - (NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error
176
176
  {
177
- return [FBScreenshot takeInOriginalResolutionWithQuality:FBConfiguration.screenshotQuality
177
+ return [FBScreenshot takeInOriginalResolutionWithQuality:FBConfiguration.sharedInstance.screenshotQuality
178
178
  error:error];
179
179
  }
180
180
 
@@ -59,7 +59,7 @@ static UIInterfaceOrientation FBInterfaceOrientationFromDeviceOrientation(UIDevi
59
59
  {
60
60
  // Tapping elements immediately after rotation may fail due to way UIKit is handling touches.
61
61
  // We should wait till UI cools off, before continuing
62
- [application fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
62
+ [application fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.animationCoolOffTimeout];
63
63
 
64
64
  return application.interfaceOrientation == FBInterfaceOrientationFromDeviceOrientation(orientation);
65
65
  }
@@ -109,7 +109,7 @@
109
109
  id<FBXCElementSnapshot> snapshot = matchingSnapshots.firstObject;
110
110
  matchingSnapshots = @[snapshot];
111
111
  }
112
- XCUIElement *scopeRoot = FBConfiguration.limitXpathContextScope ? self : self.application;
112
+ XCUIElement *scopeRoot = FBConfiguration.sharedInstance.limitXpathContextScope ? self : self.application;
113
113
  return [scopeRoot fb_filterDescendantsWithSnapshots:matchingSnapshots
114
114
  onlyChildren:NO];
115
115
  }
@@ -198,7 +198,7 @@ const CGFloat FBScrollTouchProportion = 0.75f;
198
198
  }
199
199
  scrollCount++;
200
200
  // Wait for scroll animation
201
- [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
201
+ [self fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.animationCoolOffTimeout];
202
202
  }
203
203
  }
204
204
 
@@ -24,7 +24,7 @@ int const MAX_ITERATIONS_COUNT = 100;
24
24
 
25
25
  - (BOOL)fb_setFocusWithError:(NSError**) error
26
26
  {
27
- [XCUIApplication.fb_activeApplication fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
27
+ [XCUIApplication.fb_activeApplication fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.animationCoolOffTimeout];
28
28
 
29
29
  if (!self.wdEnabled) {
30
30
  if (error) {
@@ -100,7 +100,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
100
100
  {
101
101
  return [self fb_typeText:text
102
102
  shouldClear:shouldClear
103
- frequency:FBConfiguration.maxTypingFrequency
103
+ frequency:FBConfiguration.sharedInstance.maxTypingFrequency
104
104
  error:error];
105
105
  }
106
106
 
@@ -184,7 +184,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
184
184
  [self fb_prepareForTextInputWithSnapshot:snapshot];
185
185
  }
186
186
 
187
- if (retry == 0 && FBConfiguration.useClearTextShortcut) {
187
+ if (retry == 0 && FBConfiguration.sharedInstance.useClearTextShortcut) {
188
188
  // 1st attempt is via the IOHIDEvent as the fastest operation
189
189
  // https://github.com/appium/appium/issues/19389
190
190
  [[XCUIDevice sharedDevice] fb_performIOHIDEventWithPage:0x07 // kHIDPage_KeyboardOrKeypad
@@ -194,8 +194,8 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
194
194
  } else if (retry >= MAX_CLEAR_RETRIES - 1) {
195
195
  // Last chance retry. Tripple-tap the field to select its content
196
196
  [self tapWithNumberOfTaps:3 numberOfTouches:1];
197
- return FBTypeText(backspaceDeleteSequence, FBConfiguration.defaultTypingFrequency, error);
198
- } else if (!FBTypeText(backspacesToType, FBConfiguration.defaultTypingFrequency, error)) {
197
+ return FBTypeText(backspaceDeleteSequence, FBConfiguration.sharedInstance.defaultTypingFrequency, error);
198
+ } else if (!FBTypeText(backspacesToType, FBConfiguration.sharedInstance.defaultTypingFrequency, error)) {
199
199
  // 2nd operation
200
200
  return NO;
201
201
  }
@@ -215,7 +215,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
215
215
  // kHIDPage_KeyboardOrKeypad did not work for tvOS's search field. (tvOS 17 at least)
216
216
  // Tested XCUIElementTypeSearchField and XCUIElementTypeTextView whch were
217
217
  // common search field and email/passowrd input in tvOS apps.
218
- return FBTypeText(backspacesToType, FBConfiguration.defaultTypingFrequency, error);
218
+ return FBTypeText(backspacesToType, FBConfiguration.sharedInstance.defaultTypingFrequency, error);
219
219
  #endif
220
220
  }
221
221
 
@@ -130,7 +130,7 @@
130
130
 
131
131
  - (void)fb_waitUntilStable
132
132
  {
133
- [self fb_waitUntilStableWithTimeout:FBConfiguration.waitForIdleTimeout];
133
+ [self fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.waitForIdleTimeout];
134
134
  }
135
135
 
136
136
  - (void)fb_waitUntilStableWithTimeout:(NSTimeInterval)timeout
@@ -139,9 +139,9 @@
139
139
  return;
140
140
  }
141
141
 
142
- NSTimeInterval previousTimeout = FBConfiguration.waitForIdleTimeout;
142
+ NSTimeInterval previousTimeout = FBConfiguration.sharedInstance.waitForIdleTimeout;
143
143
  BOOL previousQuiescence = self.application.fb_shouldWaitForQuiescence;
144
- FBConfiguration.waitForIdleTimeout = timeout;
144
+ FBConfiguration.sharedInstance.waitForIdleTimeout = timeout;
145
145
  if (!previousQuiescence) {
146
146
  self.application.fb_shouldWaitForQuiescence = YES;
147
147
  }
@@ -150,7 +150,7 @@
150
150
  if (previousQuiescence != self.application.fb_shouldWaitForQuiescence) {
151
151
  self.application.fb_shouldWaitForQuiescence = previousQuiescence;
152
152
  }
153
- FBConfiguration.waitForIdleTimeout = previousTimeout;
153
+ FBConfiguration.sharedInstance.waitForIdleTimeout = previousTimeout;
154
154
  }
155
155
 
156
156
  - (void)fb_raiseStaleElementExceptionWithError:(NSError *)error __attribute__((noreturn))
@@ -37,7 +37,7 @@
37
37
  return [self fb_nativeSnapshot];
38
38
  }
39
39
  // https://github.com/appium/WebDriverAgent/issues/1085
40
- if (FBConfiguration.enforceCustomSnapshots) {
40
+ if (FBConfiguration.sharedInstance.enforceCustomSnapshots) {
41
41
  return [self fb_customSnapshot];
42
42
  }
43
43
  // https://github.com/appium/appium-xcuitest-driver/issues/2552
@@ -219,7 +219,7 @@
219
219
  [element adjustToNormalizedSliderPosition:sliderValue];
220
220
  return FBResponseWithOK();
221
221
  }
222
- NSUInteger frequency = (NSUInteger)[request.arguments[@"frequency"] longLongValue] ?: [FBConfiguration maxTypingFrequency];
222
+ NSUInteger frequency = (NSUInteger)[request.arguments[@"frequency"] longLongValue] ?: FBConfiguration.sharedInstance.maxTypingFrequency;
223
223
  NSError *error = nil;
224
224
  // checkStaleness:YES above already took a fresh, verified-live snapshot of
225
225
  // `element` and cached it as `lastSnapshot` - reuse it instead of paying
@@ -292,7 +292,7 @@
292
292
  if (![element fb_setFocusWithError:&error]) {
293
293
  return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description traceback:nil]);
294
294
  }
295
- return FBResponseWithStatus([FBCommandStatus okWithValue: FBDictionaryResponseWithElement(element, FBConfiguration.shouldUseCompactResponses)]);
295
+ return FBResponseWithStatus([FBCommandStatus okWithValue: FBDictionaryResponseWithElement(element, FBConfiguration.sharedInstance.shouldUseCompactResponses)]);
296
296
  }
297
297
  #else
298
298
  + (id<FBResponsePayload>)handleDoubleTap:(FBRouteRequest *)request
@@ -520,7 +520,7 @@
520
520
  + (id<FBResponsePayload>)handleKeys:(FBRouteRequest *)request
521
521
  {
522
522
  NSString *textToType = [request.arguments[@"value"] componentsJoinedByString:@""];
523
- NSUInteger frequency = [request.arguments[@"frequency"] unsignedIntegerValue] ?: [FBConfiguration maxTypingFrequency];
523
+ NSUInteger frequency = [request.arguments[@"frequency"] unsignedIntegerValue] ?: FBConfiguration.sharedInstance.maxTypingFrequency;
524
524
  NSError *error;
525
525
  if (!FBTypeText(textToType, frequency, &error)) {
526
526
  return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
@@ -63,7 +63,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
63
63
  if (!element) {
64
64
  return FBNoSuchElementErrorResponseForRequest(request);
65
65
  }
66
- return FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
66
+ return FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
67
67
  }
68
68
 
69
69
  + (id<FBResponsePayload>)handleFindElements:(FBRouteRequest *)request
@@ -73,7 +73,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
73
73
  withValue:request.arguments[@"value"]
74
74
  under:session.activeApplication
75
75
  shouldReturnAfterFirstMatch:NO];
76
- return FBResponseWithCachedElements(elements, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
76
+ return FBResponseWithCachedElements(elements, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
77
77
  }
78
78
 
79
79
  + (id<FBResponsePayload>)handleFindVisibleCells:(FBRouteRequest *)request
@@ -87,7 +87,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
87
87
  }];
88
88
  NSArray *cells = [element fb_filterDescendantsWithSnapshots:visibleCellSnapshots
89
89
  onlyChildren:NO];
90
- return FBResponseWithCachedElements(cells, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
90
+ return FBResponseWithCachedElements(cells, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
91
91
  }
92
92
 
93
93
  + (id<FBResponsePayload>)handleFindSubElement:(FBRouteRequest *)request
@@ -101,7 +101,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
101
101
  if (!foundElement) {
102
102
  return FBNoSuchElementErrorResponseForRequest(request);
103
103
  }
104
- return FBResponseWithCachedElement(foundElement, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
104
+ return FBResponseWithCachedElement(foundElement, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
105
105
  }
106
106
 
107
107
  + (id<FBResponsePayload>)handleFindSubElements:(FBRouteRequest *)request
@@ -113,7 +113,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
113
113
  withValue:request.arguments[@"value"]
114
114
  under:element
115
115
  shouldReturnAfterFirstMatch:NO];
116
- return FBResponseWithCachedElements(foundElements, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
116
+ return FBResponseWithCachedElements(foundElements, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
117
117
  }
118
118
 
119
119
  + (id<FBResponsePayload>)handleGetActiveElement:(FBRouteRequest *)request
@@ -122,7 +122,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
122
122
  if (nil == element) {
123
123
  return FBNoSuchElementErrorResponseForRequest(request);
124
124
  }
125
- return FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
125
+ return FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
126
126
  }
127
127
 
128
128
  #if TARGET_OS_TV
@@ -131,7 +131,7 @@ static id<FBResponsePayload> FBNoSuchElementErrorResponseForRequest(FBRouteReque
131
131
  XCUIElement *element = request.session.activeApplication.fb_focusedElement;
132
132
  return element == nil
133
133
  ? FBNoSuchElementErrorResponseForRequest(request)
134
- : FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.shouldUseCompactResponses);
134
+ : FBResponseWithCachedElement(element, request.session.elementCache, FBConfiguration.sharedInstance.shouldUseCompactResponses);
135
135
  }
136
136
  #endif
137
137
 
@@ -264,29 +264,29 @@
264
264
 
265
265
  + (void)applyConfigurationFromCapabilities:(NSDictionary<NSString *, id> *)capabilities
266
266
  {
267
- [FBConfiguration resetSessionSettings];
267
+ [FBConfiguration.sharedInstance resetSessionSettings];
268
268
  if (capabilities[FB_SETTING_USE_COMPACT_RESPONSES]) {
269
- [FBConfiguration setShouldUseCompactResponses:[capabilities[FB_SETTING_USE_COMPACT_RESPONSES] boolValue]];
269
+ FBConfiguration.sharedInstance.shouldUseCompactResponses = [capabilities[FB_SETTING_USE_COMPACT_RESPONSES] boolValue];
270
270
  }
271
271
  NSString *elementResponseAttributes = capabilities[FB_SETTING_ELEMENT_RESPONSE_ATTRIBUTES];
272
272
  if (elementResponseAttributes) {
273
- [FBConfiguration setElementResponseAttributes:elementResponseAttributes];
273
+ FBConfiguration.sharedInstance.elementResponseAttributes = elementResponseAttributes;
274
274
  }
275
275
  if (capabilities[FB_CAP_MAX_TYPING_FREQUENCY]) {
276
- [FBConfiguration setMaxTypingFrequency:[capabilities[FB_CAP_MAX_TYPING_FREQUENCY] unsignedIntegerValue]];
276
+ FBConfiguration.sharedInstance.maxTypingFrequency = [capabilities[FB_CAP_MAX_TYPING_FREQUENCY] unsignedIntegerValue];
277
277
  }
278
278
  if (capabilities[FB_CAP_USE_SINGLETON_TEST_MANAGER]) {
279
- [FBConfiguration setShouldUseSingletonTestManager:[capabilities[FB_CAP_USE_SINGLETON_TEST_MANAGER] boolValue]];
279
+ FBConfiguration.sharedInstance.shouldUseSingletonTestManager = [capabilities[FB_CAP_USE_SINGLETON_TEST_MANAGER] boolValue];
280
280
  }
281
281
  if (capabilities[FB_CAP_DISABLE_AUTOMATIC_SCREENSHOTS]) {
282
282
  if ([capabilities[FB_CAP_DISABLE_AUTOMATIC_SCREENSHOTS] boolValue]) {
283
- [FBConfiguration disableScreenshots];
283
+ [FBConfiguration.sharedInstance disableScreenshots];
284
284
  } else {
285
- [FBConfiguration enableScreenshots];
285
+ [FBConfiguration.sharedInstance enableScreenshots];
286
286
  }
287
287
  }
288
288
  if (capabilities[FB_CAP_SHOULD_TERMINATE_APP]) {
289
- [FBConfiguration setShouldTerminateApp:[capabilities[FB_CAP_SHOULD_TERMINATE_APP] boolValue]];
289
+ FBConfiguration.sharedInstance.shouldTerminateApp = [capabilities[FB_CAP_SHOULD_TERMINATE_APP] boolValue];
290
290
  }
291
291
  NSNumber *delay = capabilities[FB_CAP_EVENT_LOOP_IDLE_DELAY_SEC];
292
292
  if ([delay doubleValue] > 0.0) {
@@ -295,11 +295,11 @@
295
295
  [XCUIApplicationProcessDelay disableEventLoopDelay];
296
296
  }
297
297
  if (nil != capabilities[FB_SETTING_WAIT_FOR_IDLE_TIMEOUT]) {
298
- FBConfiguration.waitForIdleTimeout = [capabilities[FB_SETTING_WAIT_FOR_IDLE_TIMEOUT] doubleValue];
298
+ FBConfiguration.sharedInstance.waitForIdleTimeout = [capabilities[FB_SETTING_WAIT_FOR_IDLE_TIMEOUT] doubleValue];
299
299
  }
300
300
  if (nil == capabilities[FB_CAP_FORCE_SIMULATOR_SOFTWARE_KEYBOARD_PRESENCE] ||
301
301
  [capabilities[FB_CAP_FORCE_SIMULATOR_SOFTWARE_KEYBOARD_PRESENCE] boolValue]) {
302
- [FBConfiguration forceSimulatorSoftwareKeyboardPresence];
302
+ [FBConfiguration.sharedInstance forceSimulatorSoftwareKeyboardPresence];
303
303
  }
304
304
  }
305
305
 
@@ -200,7 +200,7 @@
200
200
  id<FBXCElementSnapshot> snapshot = dstField.fb_cachedSnapshot ?: [dstField fb_standardSnapshot];
201
201
  if (![dstField fb_typeText:text
202
202
  shouldClear:YES
203
- frequency:FBConfiguration.maxTypingFrequency
203
+ frequency:FBConfiguration.sharedInstance.maxTypingFrequency
204
204
  snapshot:snapshot
205
205
  error:&error]) {
206
206
  [self fb_raiseSetTextFailedExceptionWithReason:error.description];
@@ -236,17 +236,17 @@
236
236
  }
237
237
 
238
238
  XCUIElement *acceptButton = nil;
239
- if (FBConfiguration.acceptAlertButtonSelector.length) {
239
+ if (FBConfiguration.sharedInstance.acceptAlertButtonSelector.length) {
240
240
  NSString *errorReason = nil;
241
241
  @try {
242
- acceptButton = [[alertElement fb_descendantsMatchingClassChain:FBConfiguration.acceptAlertButtonSelector
242
+ acceptButton = [[alertElement fb_descendantsMatchingClassChain:FBConfiguration.sharedInstance.acceptAlertButtonSelector
243
243
  shouldReturnAfterFirstMatch:YES] firstObject];
244
244
  } @catch (NSException *ex) {
245
245
  errorReason = ex.reason;
246
246
  }
247
247
  if (nil == acceptButton) {
248
248
  [FBLogger logFmt:@"Cannot find any match for Accept alert button using the class chain selector '%@'",
249
- FBConfiguration.acceptAlertButtonSelector];
249
+ FBConfiguration.sharedInstance.acceptAlertButtonSelector];
250
250
  if (nil != errorReason) {
251
251
  [FBLogger logFmt:@"Original error: %@", errorReason];
252
252
  }
@@ -293,17 +293,17 @@
293
293
  }
294
294
 
295
295
  XCUIElement *dismissButton = nil;
296
- if (FBConfiguration.dismissAlertButtonSelector.length) {
296
+ if (FBConfiguration.sharedInstance.dismissAlertButtonSelector.length) {
297
297
  NSString *errorReason = nil;
298
298
  @try {
299
- dismissButton = [[alertElement fb_descendantsMatchingClassChain:FBConfiguration.dismissAlertButtonSelector
299
+ dismissButton = [[alertElement fb_descendantsMatchingClassChain:FBConfiguration.sharedInstance.dismissAlertButtonSelector
300
300
  shouldReturnAfterFirstMatch:YES] firstObject];
301
301
  } @catch (NSException *ex) {
302
302
  errorReason = ex.reason;
303
303
  }
304
304
  if (nil == dismissButton) {
305
305
  [FBLogger logFmt:@"Cannot find any match for Dismiss alert button using the class chain selector '%@'",
306
- FBConfiguration.dismissAlertButtonSelector];
306
+ FBConfiguration.sharedInstance.dismissAlertButtonSelector];
307
307
  if (nil != errorReason) {
308
308
  [FBLogger logFmt:@"Original error: %@", errorReason];
309
309
  }
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>16.1.7</string>
18
+ <string>16.2.1</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>16.1.7</string>
22
+ <string>16.2.1</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -120,7 +120,7 @@ inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL
120
120
 
121
121
  NSMutableDictionary *result = compactResult.mutableCopy;
122
122
  FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
123
- NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","];
123
+ NSArray *fields = [FBConfiguration.sharedInstance.elementResponseAttributes componentsSeparatedByString:@","];
124
124
  for (NSString *field in fields) {
125
125
  // 'name' here is the w3c-approved identifier for what we mean by 'type'
126
126
  if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) {
@@ -52,7 +52,7 @@ NSString *const FB_SAFARI_BUNDLE_ID = @"com.apple.mobilesafari";
52
52
 
53
53
  - (void)didDetectAlert:(FBAlert *)alert
54
54
  {
55
- NSString *autoClickAlertSelector = FBConfiguration.autoClickAlertSelector;
55
+ NSString *autoClickAlertSelector = FBConfiguration.sharedInstance.autoClickAlertSelector;
56
56
  if ([autoClickAlertSelector length] > 0) {
57
57
  @try {
58
58
  [alert clickElementMatchingClassChain:autoClickAlertSelector];
@@ -185,7 +185,7 @@ static FBSession *_activeSession = nil;
185
185
  }
186
186
 
187
187
  if (nil != self.testedApplication
188
- && FBConfiguration.shouldTerminateApp
188
+ && FBConfiguration.sharedInstance.shouldTerminateApp
189
189
  && self.testedApplication.running
190
190
  && ![self.testedApplication fb_isSameAppAs:XCUIApplication.fb_systemApplication]) {
191
191
  @try {
@@ -217,7 +217,7 @@ static FBSession *_activeSession = nil;
217
217
  // To look for 'criticalAlertSetting' elements https://developer.apple.com/documentation/usernotifications/unnotificationsettings/criticalalertsetting
218
218
  // See https://github.com/appium/appium/issues/20835
219
219
  @"NotificationShortLookView"];
220
- if ([FBConfiguration shouldRespectSystemAlerts]
220
+ if (FBConfiguration.sharedInstance.shouldRespectSystemAlerts
221
221
  && [[XCUIApplication.fb_systemApplication descendantsMatchingType:XCUIElementTypeAny]
222
222
  matchingPredicate:searchPredicate].count > 0) {
223
223
  return XCUIApplication.fb_systemApplication;
@@ -41,7 +41,7 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
41
41
 
42
42
  - (UInt64)maxRequestBodySize
43
43
  {
44
- return FBConfiguration.httpRequestBodySizeLimit;
44
+ return FBConfiguration.sharedInstance.httpRequestBodySizeLimit;
45
45
  }
46
46
 
47
47
  @end
@@ -104,8 +104,8 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
104
104
  [self registerRouteHandlers:[self.class collectCommandHandlerClasses]];
105
105
  [self registerServerKeyRouteHandlers];
106
106
 
107
- NSRange serverPortRange = FBConfiguration.bindingPortRange;
108
- NSString *bindingIP = FBConfiguration.bindingIPAddress;
107
+ NSRange serverPortRange = FBConfiguration.sharedInstance.bindingPortRange;
108
+ NSString *bindingIP = FBConfiguration.sharedInstance.bindingIPAddress;
109
109
  if (bindingIP != nil) {
110
110
  [self.server setInterface:bindingIP];
111
111
  [FBLogger logFmt:@"Using custom binding IP address: %@", bindingIP];
@@ -146,11 +146,11 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
146
146
  [self readMjpegSettingsFromEnv];
147
147
  self.mjpegServer = [[FBMjpegServer alloc] init];
148
148
  self.screenshotsBroadcaster = [[FBTCPSocket alloc]
149
- initWithPort:(uint16_t)FBConfiguration.mjpegServerPort];
149
+ initWithPort:(uint16_t)FBConfiguration.sharedInstance.mjpegServerPort];
150
150
  self.screenshotsBroadcaster.delegate = self.mjpegServer;
151
151
  NSError *error;
152
152
  if (![self.screenshotsBroadcaster startWithError:&error]) {
153
- [FBLogger logFmt:@"Cannot init screenshots broadcaster service on port %@. Original error: %@", @(FBConfiguration.mjpegServerPort), error.description];
153
+ [FBLogger logFmt:@"Cannot init screenshots broadcaster service on port %@. Original error: %@", @(FBConfiguration.sharedInstance.mjpegServerPort), error.description];
154
154
  [self.mjpegServer stopStreaming];
155
155
  self.mjpegServer = nil;
156
156
  self.screenshotsBroadcaster = nil;
@@ -179,11 +179,11 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
179
179
  NSDictionary *env = NSProcessInfo.processInfo.environment;
180
180
  NSString *scalingFactor = [env objectForKey:@"MJPEG_SCALING_FACTOR"];
181
181
  if (scalingFactor != nil && [scalingFactor length] > 0) {
182
- [FBConfiguration setMjpegScalingFactor:[scalingFactor floatValue]];
182
+ FBConfiguration.sharedInstance.mjpegScalingFactor = [scalingFactor floatValue];
183
183
  }
184
184
  NSString *screenshotQuality = [env objectForKey:@"MJPEG_SERVER_SCREENSHOT_QUALITY"];
185
185
  if (screenshotQuality != nil && [screenshotQuality length] > 0) {
186
- [FBConfiguration setMjpegServerScreenshotQuality:[screenshotQuality integerValue]];
186
+ FBConfiguration.sharedInstance.mjpegServerScreenshotQuality = [screenshotQuality integerValue];
187
187
  }
188
188
  }
189
189