From 006c2384680e36d925aaad11cdadf347c559423b Mon Sep 17 00:00:00 2001 From: timo <44401485+Timo972@users.noreply.github.com> Date: Fri, 25 Sep 2026 10:29:29 +0200 Subject: [PATCH] test: accept the iOS 27 "Start Sharing" broadcast label iOS 27 keeps ReplayKit's CONTROL_CENTER_START_BROADCAST key but renames its text from "Start Broadcast" to "Start Sharing" (German "Jetzt teilen"). The key-based lookup already resolves the new labels; the unit test asserted the old iOS 26 text and failed on the Xcode 27 simulator. Also add "Start Sharing" to the English last-resort labels. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../Utilities/FBBroadcastManager.h | 3 ++- .../Utilities/FBBroadcastManager.m | 18 ++++++++++-------- .../UnitTests/FBBroadcastLabelsTests.m | 8 +++++--- docs/broadcast-extension.md | 5 +++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/WebDriverAgentLib/Utilities/FBBroadcastManager.h b/WebDriverAgentLib/Utilities/FBBroadcastManager.h index 27a0425b7..1ff97badc 100644 --- a/WebDriverAgentLib/Utilities/FBBroadcastManager.h +++ b/WebDriverAgentLib/Utilities/FBBroadcastManager.h @@ -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. diff --git a/WebDriverAgentLib/Utilities/FBBroadcastManager.m b/WebDriverAgentLib/Utilities/FBBroadcastManager.m index 115a45cb4..ec348c52b 100644 --- a/WebDriverAgentLib/Utilities/FBBroadcastManager.m +++ b/WebDriverAgentLib/Utilities/FBBroadcastManager.m @@ -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 *FBBroadcastLabels(NSArray *_Nullable callerLabels, NSString *replayKitKey, - NSString *englishLabel) + NSArray *englishLabels) { NSMutableOrderedSet *labels = [NSMutableOrderedSet orderedSet]; [labels addObjectsFromArray:callerLabels ?: @[]]; [labels addObjectsFromArray:[FBBroadcastManager replayKitLabelsForKey:replayKitKey]]; - [labels addObject:englishLabel]; + [labels addObjectsFromArray:englishLabels]; return labels.array; } @@ -362,8 +364,8 @@ - (BOOL)performBroadcastStartWithTimeout:(NSTimeInterval)timeout restoreForegroundApp:(BOOL)restoreForegroundApp error:(NSError **)error { - NSArray *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @"OK"); - NSArray *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @"Go to Application"); + NSArray *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @[@"OK"]); + NSArray *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 @@ -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 *labels = FBBroadcastLabels(confirmButtonLabels, FBReplayKitKeyStartBroadcast, @"Start Broadcast"); + NSArray *labels = FBBroadcastLabels(confirmButtonLabels, FBReplayKitKeyStartBroadcast, @[@"Start Broadcast", @"Start Sharing"]); NSPredicate *labelPredicate = [NSPredicate predicateWithFormat:@"label IN %@", labels]; NSArray *candidateApps = @[XCUIApplication.fb_systemApplication, runner]; __block BOOL confirmButtonFound = NO; @@ -673,8 +675,8 @@ - (BOOL)stopBroadcastWithDismissButtonLabels:(NSArray *)dismissButto error:(NSError **)error { #if !TARGET_OS_SIMULATOR && !TARGET_OS_TV - NSArray *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @"OK"); - NSArray *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @"Go to Application"); + NSArray *dismissLabels = FBBroadcastLabels(dismissButtonLabels, FBReplayKitKeyAlertOK, @[@"OK"]); + NSArray *goToAppLabels = FBBroadcastLabels(goToApplicationButtonLabels, FBReplayKitKeyAlertGoToApp, @[@"Go to Application"]); #endif if (!self.isExtensionConnected) { #if !TARGET_OS_SIMULATOR && !TARGET_OS_TV diff --git a/WebDriverAgentTests/UnitTests/FBBroadcastLabelsTests.m b/WebDriverAgentTests/UnitTests/FBBroadcastLabelsTests.m index e99c2ebe0..ab70ded02 100644 --- a/WebDriverAgentTests/UnitTests/FBBroadcastLabelsTests.m +++ b/WebDriverAgentTests/UnitTests/FBBroadcastLabelsTests.m @@ -18,10 +18,12 @@ @implementation FBBroadcastLabelsTests - (void)testStartBroadcastLabelCoversNonEnglishLanguages { NSArray *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); } diff --git a/docs/broadcast-extension.md b/docs/broadcast-extension.md index f1bc687e1..ea2b80b79 100644 --- a/docs/broadcast-extension.md +++ b/docs/broadcast-extension.md @@ -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.