Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion WebDriverAgentLib/Utilities/FBBroadcastManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ typedef NS_ERROR_ENUM(FBBroadcastManagerErrorDomain, FBBroadcastManagerError) {

/**
Every localized variant ReplayKit ships for one of its UI strings, e.g.
"CONTROL_CENTER_START_BROADCAST" ("Start Broadcast", "Übertragung starten", ...). The device's
"CONTROL_CENTER_START_BROADCAST" ("Start Broadcast", "Übertragung starten", ...; "Start
Sharing", "Jetzt teilen", ... since iOS 27). The device's
preferred localizations come first; the set covers all languages so that matching does not
depend on which language the system UI is currently rendered in. Resolved from the ReplayKit
framework's own localization tables once per key and cached.
Expand Down
18 changes: 10 additions & 8 deletions WebDriverAgentLib/Utilities/FBBroadcastManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,17 @@
static NSString *const FBReplayKitKeyAlertGoToApp = @"BROADCAST_FAILED_ALERT_GO_TO_APP_BUTTON";

// Caller-supplied labels first, then the system's own label in every ReplayKit localization,
// then the English label as a last resort for iOS versions whose tables lack the key.
// then the known English labels as a last resort for iOS versions whose tables lack the key.
// The key is what stays stable: iOS 27 kept CONTROL_CENTER_START_BROADCAST but renamed its text
// from "Start Broadcast" to "Start Sharing".
static NSArray<NSString *> *FBBroadcastLabels(NSArray<NSString *> *_Nullable callerLabels,
NSString *replayKitKey,
NSString *englishLabel)
NSArray<NSString *> *englishLabels)
{
NSMutableOrderedSet<NSString *> *labels = [NSMutableOrderedSet orderedSet];
[labels addObjectsFromArray:callerLabels ?: @[]];
[labels addObjectsFromArray:[FBBroadcastManager replayKitLabelsForKey:replayKitKey]];
[labels addObject:englishLabel];
[labels addObjectsFromArray:englishLabels];
return labels.array;
}

Expand Down Expand Up @@ -362,8 +364,8 @@ - (BOOL)performBroadcastStartWithTimeout:(NSTimeInterval)timeout
restoreForegroundApp:(BOOL)restoreForegroundApp
error:(NSError **)error
{
NSArray<NSString *> *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @"OK");
NSArray<NSString *> *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @"Go to Application");
NSArray<NSString *> *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @[@"OK"]);
NSArray<NSString *> *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @[@"Go to Application"]);

// The screen may already be captured by a live broadcast even though the extension is not
// connected (it crashed, or it is between TCP reconnect attempts). Driving the picker on top
Expand Down Expand Up @@ -474,7 +476,7 @@ - (BOOL)performBroadcastStartWithTimeout:(NSTimeInterval)timeout

// The confirmation sheet is hosted by different processes depending on the iOS version, so
// look for the confirm button in both the system app and the runner itself.
NSArray<NSString *> *labels = FBBroadcastLabels(confirmButtonLabels, FBReplayKitKeyStartBroadcast, @"Start Broadcast");
NSArray<NSString *> *labels = FBBroadcastLabels(confirmButtonLabels, FBReplayKitKeyStartBroadcast, @[@"Start Broadcast", @"Start Sharing"]);
NSPredicate *labelPredicate = [NSPredicate predicateWithFormat:@"label IN %@", labels];
NSArray<XCUIApplication *> *candidateApps = @[XCUIApplication.fb_systemApplication, runner];
__block BOOL confirmButtonFound = NO;
Expand Down Expand Up @@ -673,8 +675,8 @@ - (BOOL)stopBroadcastWithDismissButtonLabels:(NSArray<NSString *> *)dismissButto
error:(NSError **)error
{
#if !TARGET_OS_SIMULATOR && !TARGET_OS_TV
NSArray<NSString *> *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @"OK");
NSArray<NSString *> *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @"Go to Application");
NSArray<NSString *> *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @[@"OK"]);
NSArray<NSString *> *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @[@"Go to Application"]);
#endif
if (!self.isExtensionConnected) {
#if !TARGET_OS_SIMULATOR && !TARGET_OS_TV
Expand Down
8 changes: 5 additions & 3 deletions WebDriverAgentTests/UnitTests/FBBroadcastLabelsTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ @implementation FBBroadcastLabelsTests
- (void)testStartBroadcastLabelCoversNonEnglishLanguages
{
NSArray<NSString *> *labels = [FBBroadcastManager replayKitLabelsForKey:@"CONTROL_CENTER_START_BROADCAST"];
XCTAssertTrue([labels containsObject:@"Start Broadcast"]);
// iOS 27 kept the key but renamed the button ("Start Broadcast" -> "Start Sharing"), which is
// exactly why the labels are resolved by key rather than hardcoded.
XCTAssertTrue([labels containsObject:@"Start Broadcast"] || [labels containsObject:@"Start Sharing"]);
// The German label does not start with "Start" - the case that broke the old prefix matching.
XCTAssertTrue([labels containsObject:@"Übertragung starten"]);
XCTAssertTrue([labels containsObject:@"开始直播"]);
XCTAssertTrue([labels containsObject:@"Übertragung starten"] || [labels containsObject:@"Jetzt teilen"]);
XCTAssertTrue([labels containsObject:@"开始直播"] || [labels containsObject:@"开始共享"]);
XCTAssertEqual(labels.count, [NSSet setWithArray:labels].count);
}

Expand Down
5 changes: 3 additions & 2 deletions docs/broadcast-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ the legacy screenshot pipeline; each session reports its current origin via the
```

The system UI driven by the start dance is matched in any device language: WDA reads the button
labels ("Start Broadcast", and the "Screen Broadcasting" alert's "OK" / "Go to Application")
from ReplayKit's own localization tables at runtime, in every language iOS ships. The label
labels ("Start Broadcast" - "Start Sharing" since iOS 27 - and the "Screen Broadcasting"
alert's "OK" / "Go to Application") from ReplayKit's own localization tables at runtime, in
every language iOS ships. The label
arguments below are only needed if a future iOS renames those strings; they are matched in
addition to the system labels, never instead of them.

Expand Down
Loading