Skip to content

Commit 98d79e7

Browse files
authored
fix: auto-handle iOS 18+ limited access permission prompt (#1150)
1 parent 2eb1125 commit 98d79e7

4 files changed

Lines changed: 44 additions & 2 deletions

File tree

WebDriverAgentLib/Categories/XCUIApplication+FBAlert.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#import <XCTest/XCTest.h>
1010

11+
NS_ASSUME_NONNULL_BEGIN
12+
1113
@interface XCUIApplication (FBAlert)
1214

1315
/* The accessiblity label used for Safari app */
@@ -18,6 +20,16 @@ extern NSString *const FB_SAFARI_APP_NAME;
1820
1921
@return Alert element instance
2022
*/
21-
- (XCUIElement *)fb_alertElement;
23+
- (nullable XCUIElement *)fb_alertElement;
24+
25+
/**
26+
Retrieve an alert element hosted by the iOS 18+ limited access permission prompt
27+
process. See https://github.com/appium/appium/issues/20591
28+
29+
@return Alert element instance if the prompt is present, otherwise nil
30+
*/
31+
+ (nullable XCUIElement *)fb_limitedAccessPromptAlertElement;
2232

2333
@end
34+
35+
NS_ASSUME_NONNULL_END

WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,22 @@
1717

1818
NSString *const FB_SAFARI_APP_NAME = @"Safari";
1919

20+
// The iOS 18+ limited access permission prompt (e.g. the "Select Contacts" view)
21+
// runs in a dedicated process that is not reported by fb_activeApplications.
22+
static NSString *const FB_LIMITED_ACCESS_PROMPT_BUNDLE_ID = @"com.apple.ContactsUI.LimitedAccessPromptView";
23+
2024

2125
@implementation XCUIApplication (FBAlert)
2226

27+
+ (nullable XCUIElement *)fb_limitedAccessPromptAlertElement
28+
{
29+
XCUIApplication *promptApp = [[XCUIApplication alloc] initWithBundleIdentifier:FB_LIMITED_ACCESS_PROMPT_BUNDLE_ID];
30+
if (promptApp.state < XCUIApplicationStateRunningForeground) {
31+
return nil;
32+
}
33+
return promptApp.fb_alertElement;
34+
}
35+
2336
- (nullable XCUIElement *)fb_alertElementFromSafariWithScrollView:(XCUIElement *)scrollView
2437
viewSnapshot:(id<FBXCElementSnapshot>)viewSnapshot
2538
{

WebDriverAgentLib/FBAlert.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ - (XCUIElement *)alertElement
267267
} else {
268268
self.element = systemApp.fb_alertElement ?: self.application.fb_alertElement;
269269
}
270+
if (nil == self.element) {
271+
self.element = [XCUIApplication fb_limitedAccessPromptAlertElement];
272+
}
270273
}
271274
return self.element;
272275
}

WebDriverAgentLib/Utilities/FBAlertsMonitor.m

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,36 @@ - (void)scheduleNextTick
4848
}
4949

5050
dispatch_async(dispatch_get_main_queue(), ^{
51+
id<FBAlertsMonitorDelegate> delegate = self.delegate;
5152
NSArray<XCUIApplication *> *activeApps = XCUIApplication.fb_activeApplications;
53+
BOOL didDetectAlert = NO;
5254
for (XCUIApplication *activeApp in activeApps) {
5355
XCUIElement *alertElement = nil;
5456
@try {
5557
alertElement = activeApp.fb_alertElement;
5658
if (nil != alertElement) {
57-
[self.delegate didDetectAlert:[FBAlert alertWithElement:alertElement]];
59+
[delegate didDetectAlert:[FBAlert alertWithElement:alertElement]];
5860
}
5961
} @catch (NSException *e) {
6062
[FBLogger logFmt:@"Got an unexpected exception while monitoring alerts: %@\n%@", e.reason, e.callStackSymbols];
6163
}
6264
if (nil != alertElement) {
65+
didDetectAlert = YES;
6366
break;
6467
}
6568
}
6669

70+
if (!didDetectAlert) {
71+
@try {
72+
XCUIElement *alertElement = [XCUIApplication fb_limitedAccessPromptAlertElement];
73+
if (nil != alertElement) {
74+
[delegate didDetectAlert:[FBAlert alertWithElement:alertElement]];
75+
}
76+
} @catch (NSException *e) {
77+
[FBLogger logFmt:@"Got an unexpected exception while monitoring alerts: %@\n%@", e.reason, e.callStackSymbols];
78+
}
79+
}
80+
6781
if (self.isMonitoring) {
6882
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta), dispatch_get_main_queue(), ^{
6983
[self scheduleNextTick];

0 commit comments

Comments
 (0)