Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public final class OnboardingFlowViewModel<ViewModel: OnboardingCardInfoModelPro
public let onActionTap: @MainActor (
ViewModel.OnboardingActionType,
String,
@escaping (Result<TabAction, Error>) -> Void
@MainActor @escaping (Result<TabAction, Error>) -> Void
) -> Void
public let onMultipleChoiceActionTap: (
public let onMultipleChoiceActionTap: @MainActor (
ViewModel.OnboardingMultipleChoiceActionType,
String
) -> Void
Expand All @@ -24,26 +24,26 @@ public final class OnboardingFlowViewModel<ViewModel: OnboardingCardInfoModelPro
case none
}

public let onComplete: (String) -> Void
public let onComplete: @MainActor (String) -> Void
public private(set) var multipleChoiceSelections: [String: ViewModel.OnboardingMultipleChoiceActionType] = [:]

public var onCardView: ((String) -> Void)?
public var onButtonTap: ((String, ViewModel.OnboardingActionType, Bool) -> Void)?
public var onMultipleChoiceTap: ((String, ViewModel.OnboardingMultipleChoiceActionType) -> Void)?
public var onDismiss: ((String) -> Void)?
public var onCardView: (@MainActor (String) -> Void)?
public var onButtonTap: (@MainActor (String, ViewModel.OnboardingActionType, Bool) -> Void)?
public var onMultipleChoiceTap: (@MainActor (String, ViewModel.OnboardingMultipleChoiceActionType) -> Void)?
public var onDismiss: (@MainActor (String) -> Void)?

public init(
onboardingCards: [ViewModel],
skipText: String,
onActionTap: @MainActor @escaping (
ViewModel.OnboardingActionType,
String,
@escaping (Result<TabAction, Error>) -> Void) -> Void,
onMultipleChoiceActionTap: @escaping (
@MainActor @escaping (Result<TabAction, Error>) -> Void) -> Void,
onMultipleChoiceActionTap: @MainActor @escaping (
ViewModel.OnboardingMultipleChoiceActionType,
String
) -> Void,
onComplete: @escaping (String) -> Void
onComplete: @MainActor @escaping (String) -> Void
) {
self.onboardingCards = onboardingCards
self.skipText = skipText
Expand Down
19 changes: 18 additions & 1 deletion firefox-ios/Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27948,7 +27948,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "iPhone, iPad";
TEST_TARGET_NAME = Client;
VALIDATE_PRODUCT = YES;
Comment on lines 27948 to 27954
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for Xcode/toolchain version specifications in CI and config files
echo "=== Searching for Xcode/toolchain version pins ==="
rg -n --hidden -g '!.git' -g '!node_modules' '(?i)(xcode.?version|swift.?version|developer.?dir|toolchain)' . 2>/dev/null | head -50

echo -e "\n=== Checking for CI workflow files ==="
fd -e yml -e yaml -e json '(workflow|ci|circleci|github|fastlane)' .

echo -e "\n=== Checking common CI directories ==="
ls -la .github/workflows/ 2>/dev/null || echo ".github/workflows not found"
ls -la .circleci/ 2>/dev/null || echo ".circleci not found"
ls -la fastlane/ 2>/dev/null || echo "fastlane not found"

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 7872


🏁 Script executed:

#!/bin/bash
# Check GitHub Actions workflows for Xcode version specifications
echo "=== Checking firefox-ios UI tests workflow ==="
grep -n -i "xcode\|swift" .github/workflows/firefox-ios-ui-tests.yml | head -20

echo -e "\n=== Checking firefox-ios build workflow ==="
grep -n -i "xcode\|swift" .github/workflows/firefox-ios-build-contributor-pr.yml

echo -e "\n=== Checking for macOS version specifications ==="
grep -n "macos-version\|runs-on" .github/workflows/firefox-ios-ui-tests.yml | head -10

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 1696


🏁 Script executed:

#!/bin/bash
# Check what firefox-ios-build-contributor-pr.yml actually does
cat .github/workflows/firefox-ios-build-contributor-pr.yml

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 1681


🏁 Script executed:

#!/bin/bash
# Quick verification: confirm Xcode 13.1 max Swift version
cat << 'EOF' > /tmp/check_xcode_versions.txt
Xcode Version | Max Swift Version | Release Date
13.1          | Swift 5.5         | Dec 2021
15.4          | Swift 5.9         | June 2023
16.x          | Swift 6.0         | Sept 2024
EOF
cat /tmp/check_xcode_versions.txt

# Also check if there are any references to how the build should handle different Xcode versions
echo -e "\n=== Checking for any build version handling ==="
find . -name "*.sh" -o -name "*.yml" | xargs grep -l "SWIFT_VERSION\|swift-version" | head -5

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 357


Update contributor PR workflow to support Swift 6.0 toolchain.

The main CI (Xcode 16.2) is properly configured for Swift 6.0, but the contributor PR workflow (firefox-ios-build-contributor-pr.yml) uses Xcode 13.1, which only supports Swift 5.5. This will cause all external contributor PRs to fail with Swift 6.0 compilation errors. Update the workflow to use Xcode 16.2 or later to match the production build environment.

🤖 Prompt for AI Agents
In `@firefox-ios/Client.xcodeproj/project.pbxproj` around lines 27948 - 27954, The
contributor PR workflow is still using Xcode 13.1 which does not support
SWIFT_VERSION = 6.0; update the contributor PR CI workflow to run with Xcode
16.2 or later (e.g., set the workflow's xcode-version/matrix entry or
actions/setup-xcode call to "16.2" or higher) so the build environment matches
the production Xcode 16.2 that supports Swift 6.0; ensure any matrix entries,
macOS runner selection, or setup-xcode steps in the contributor PR workflow are
updated accordingly.

Expand Down Expand Up @@ -27988,6 +27988,7 @@
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_WORKSPACE = YES;
};
Expand Down Expand Up @@ -28253,6 +28254,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = FirefoxStaging;
Expand Down Expand Up @@ -28461,6 +28463,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec_Testing;
Expand Down Expand Up @@ -28494,6 +28497,7 @@
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec_Testing;
Expand Down Expand Up @@ -28687,6 +28691,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = Fennec_Testing;
Expand Down Expand Up @@ -29771,6 +29776,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Firefox;
Expand Down Expand Up @@ -29807,6 +29813,7 @@
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Firefox;
Expand All @@ -29819,6 +29826,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = Firefox;
Expand Down Expand Up @@ -30092,6 +30100,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec_Enterprise;
Expand Down Expand Up @@ -30136,6 +30145,7 @@
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec_Enterprise;
Expand Down Expand Up @@ -30251,6 +30261,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = Fennec_Enterprise;
Expand Down Expand Up @@ -30416,6 +30427,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = FirefoxBeta;
Expand Down Expand Up @@ -30452,6 +30464,7 @@
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = FirefoxBeta;
Expand All @@ -30464,6 +30477,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = FirefoxBeta;
Expand Down Expand Up @@ -30955,6 +30969,7 @@
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_NONFROZEN_ENUM_EXHAUSTIVITY = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec;
Expand Down Expand Up @@ -30987,6 +31002,7 @@
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_VERSION = 6.0;
VALIDATE_WORKSPACE = YES;
};
name = Fennec;
Expand All @@ -30999,6 +31015,7 @@
INFOPLIST_FILE = "firefox-ios-tests/Tests/ClientTests/Info.plist";
LOCALIZATION_EXPORT_SUPPORTED = NO;
PRODUCT_NAME = ClientTests;
SWIFT_VERSION = 6.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
};
name = Fennec;
Expand Down
18 changes: 10 additions & 8 deletions firefox-ios/Client/Coordinators/Launch/LaunchCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,17 @@ final class LaunchCoordinator: BaseCoordinator,
let flowViewModel = OnboardingFlowViewModel<OnboardingKitCardInfoModel>(
onboardingCards: onboardingModel.cards,
skipText: .Onboarding.LaterAction,
onActionTap: { @MainActor [weak self] action, cardName, completion in
onActionTap: { [weak self] action, cardName, completion in
guard let onboardingService = self?.onboardingService else { return }
onboardingService.handleAction(
action,
from: cardName,
cards: onboardingModel.cards,
with: activityEventHelper,
completion: completion
)
Task {
onboardingService.handleAction(
action,
from: cardName,
cards: onboardingModel.cards,
with: activityEventHelper,
completion: completion
)
}
},
onMultipleChoiceActionTap: { [weak self] action, cardName in
guard let onboardingService = self?.onboardingService else { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ final class AutofillAccessoryViewButtonItem: UIBarButtonItem {
/// - image: The image for the accessory image view.
/// - labelText: The text for the accessory view label.
/// - tappedAction: The closure to be executed when the accessory view is tapped.
init(image: UIImage?, labelText: String, tappedAction: (() -> Void)? = nil) {
init(
image: UIImage?,
labelText: String,
tappedAction: (@MainActor () -> Void)? = nil
) {
self.accessoryImageView = .build { imageView in
imageView.image = image?.withRenderingMode(.alwaysTemplate)
imageView.contentMode = .scaleAspectFit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class WebContextMenuActionsProvider {
}

@MainActor
func addOpenInNewTab(url: URL, currentTab: Tab, addTab: @escaping (URL, Bool, Tab) -> Void) {
func addOpenInNewTab(url: URL, currentTab: Tab, addTab: @escaping @MainActor @Sendable (URL, Bool, Tab) -> Void) {
actions.append(
UIAction(
title: .ContextMenuOpenInNewTab,
Expand All @@ -41,7 +41,7 @@ class WebContextMenuActionsProvider {
}

@MainActor
func addOpenInNewPrivateTab(url: URL, currentTab: Tab, addTab: @escaping (URL, Bool, Tab) -> Void) {
func addOpenInNewPrivateTab(url: URL, currentTab: Tab, addTab: @escaping @MainActor @Sendable (URL, Bool, Tab) -> Void) {
actions.append(
UIAction(
title: .ContextMenuOpenInNewPrivateTab,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extension BrowserViewController: WKUIDelegate {
private func handleJavaScriptAlert<T: WKJavaScriptAlertInfo>(
_ alert: T,
for webView: WKWebView,
spamCallback: @escaping () -> Void
spamCallback: @escaping @MainActor @Sendable () -> Void
) {
if jsAlertExceedsSpamLimits(webView) {
handleSpammedJSAlert(spamCallback)
Expand All @@ -95,7 +95,7 @@ extension BrowserViewController: WKUIDelegate {
_ webView: WKWebView,
runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping @MainActor () -> Void
completionHandler: @escaping @MainActor @Sendable () -> Void
) {
let messageAlert = MessageAlert(message: message,
frame: frame,
Expand All @@ -110,7 +110,7 @@ extension BrowserViewController: WKUIDelegate {
_ webView: WKWebView,
runJavaScriptConfirmPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping @MainActor (Bool) -> Void
completionHandler: @escaping @MainActor @Sendable (Bool) -> Void
) {
let confirmAlert = ConfirmPanelAlert(message: message, frame: frame) { confirm in
self.logger.log("JavaScript confirm panel was completed with result: \(confirm)", level: .info, category: .webview)
Expand All @@ -127,7 +127,7 @@ extension BrowserViewController: WKUIDelegate {
runJavaScriptTextInputPanelWithPrompt prompt: String,
defaultText: String?,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping @MainActor (String?) -> Void
completionHandler: @escaping @MainActor @Sendable (String?) -> Void
) {
let textInputAlert = TextInputAlert(message: prompt, frame: frame, defaultText: defaultText) { input in
self.logger.log("JavaScript text input panel was completed with input", level: .info, category: .webview)
Expand All @@ -153,7 +153,7 @@ extension BrowserViewController: WKUIDelegate {
func webView(
_ webView: WKWebView,
contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo,
completionHandler: @escaping @MainActor (UIContextMenuConfiguration?) -> Void
completionHandler: @escaping @MainActor @Sendable (UIContextMenuConfiguration?) -> Void
) {
guard let url = elementInfo.linkURL,
let currentTab = tabManager.selectedTab,
Expand Down Expand Up @@ -184,7 +184,7 @@ extension BrowserViewController: WKUIDelegate {
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping @MainActor (WKPermissionDecision) -> Void
decisionHandler: @escaping @MainActor @Sendable (WKPermissionDecision) -> Void
) {
// If the tab isn't the selected one or we're on the homepage, do not show the media capture prompt
guard tabManager.selectedTab?.webView === webView, !contentContainer.hasAnyHomepage else {
Expand Down Expand Up @@ -312,7 +312,7 @@ extension BrowserViewController: WKUIDelegate {

func createActions(isPrivate: Bool,
url: URL,
addTab: @escaping (URL, Bool, Tab) -> Void,
addTab: @escaping @MainActor @Sendable (URL, Bool, Tab) -> Void,
title: String?,
image: URL?,
currentTab: Tab,
Expand Down Expand Up @@ -705,7 +705,7 @@ extension BrowserViewController: WKNavigationDelegate {
func webView(
_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping @MainActor (WKNavigationResponsePolicy) -> Void
decisionHandler: @escaping @MainActor @Sendable (WKNavigationResponsePolicy) -> Void
) {
let response = navigationResponse.response
let responseURL = response.url
Expand Down Expand Up @@ -1053,7 +1053,7 @@ extension BrowserViewController: WKNavigationDelegate {
func webView(
_ webView: WKWebView,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping @Sendable @MainActor (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
completionHandler: @escaping @MainActor @Sendable (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
guard challenge.protectionSpace.authenticationMethod != NSURLAuthenticationMethodServerTrust else {
handleServerTrust(
Expand Down Expand Up @@ -1232,7 +1232,7 @@ private extension BrowserViewController {

// Use for sms and mailto, which do not show a confirmation before opening.
func showExternalAlert(withText text: String,
completion: @escaping (UIAlertAction) -> Void) {
completion: @escaping @MainActor @Sendable (UIAlertAction) -> Void) {
let alert = UIAlertController(title: nil,
message: text,
preferredStyle: .alert)
Expand Down Expand Up @@ -1329,7 +1329,7 @@ private extension BrowserViewController {
func handleServerTrust(
challenge: URLAuthenticationChallenge,
dispatchQueue: DispatchQueueInterface,
completionHandler: @escaping @Sendable @MainActor (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
completionHandler: @escaping @MainActor @Sendable (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
dispatchQueue.async {
// If this is a certificate challenge, see if the certificate has previously been
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BrowserWebUIDelegate: NSObject, WKUIDelegate {
_ webView: WKWebView,
runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping @MainActor @Sendable () -> Void
completionHandler: @escaping @MainActor () -> Void
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "BrowserWebUIDelegate.swift" -type f

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 197


🏁 Script executed:

cat -n ./firefox-ios/Client/Frontend/Browser/BrowserViewController/WebEngineIntegration/BrowserWebUIDelegate.swift | head -120

Repository: qodo-benchmark/firefox-ios-combined-coderabbit

Length of output: 4953


🌐 Web query:

Apple WebKit WKUIDelegate runJavaScriptAlertPanelWithMessage Swift 6 Sendable requirement

💡 Result:

In Xcode 16 / Swift 6, a number of WebKit delegate APIs were re-imported with stricter concurrency annotations. For WKUIDelegate’s JavaScript panels, the completionHandler is now main-actor isolated (and main-actor-isolated closures are treated as @Sendable in Swift 6), so your delegate method must match that signature exactly (or use the new async overload). [1], [2]

Fix (sync completionHandler form)

Update your implementation to:

func webView(
  _ webView: WKWebView,
  runJavaScriptAlertPanelWithMessage message: String,
  initiatedByFrame frame: WKFrameInfo,
  completionHandler: `@escaping` `@MainActor` () -> Void
) {
  let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
  alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
    Task { `@MainActor` in completionHandler() }
  })
  present(alert, animated: true)
}

If you keep the old @escaping () -> Void signature, it may still compile in some configurations but won’t satisfy the protocol requirement, so the method may not be called. [1], [3]

Alternative fix (use the async overload)

Some SDKs also offer an async version of these delegate methods; implementing that overload avoids the completion-handler annotations altogether. [3]

If you must support older Xcodes too

Use conditional compilation to provide both signatures:

`#if` compiler(>=6)
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
             initiatedByFrame frame: WKFrameInfo,
             completionHandler: `@escaping` `@MainActor` () -> Void) { /*...*/ }
`#else`
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
             initiatedByFrame frame: WKFrameInfo,
             completionHandler: `@escaping` () -> Void) { /*...*/ }
`#endif`

Sources:
[1] Swift Forums discussion: global-actor-isolated closures (e.g. @MainActor) are implicitly @Sendable in Swift 6 (SE-0434 behavior). (forums.swift.org)
[2] Apple Developer Forums example of WebKit completion handlers gaining @MainActor and @Sendable in Xcode 16. (developer.apple.com)
[3] Stack Overflow report that WKUIDelegate JavaScript panel method stopped being called in Xcode 16 unless using updated/async signature. (stackoverflow.com)

Citations:


Add @Sendable annotation for consistency with other completion handlers in this file.

The completionHandler on line 42 lacks @Sendable while all other similar completion handler parameters in this file (lines 56, 71, 89, 107) include it. In Swift 6, main-actor-isolated closures are implicitly @Sendable (per SE-0434), but explicitly annotating it maintains consistency and clarity across the delegate implementation.

Suggested change
     func webView(
         _ webView: WKWebView,
         runJavaScriptAlertPanelWithMessage message: String,
         initiatedByFrame frame: WKFrameInfo,
-        completionHandler: `@escaping` `@MainActor` () -> Void
+        completionHandler: `@escaping` `@MainActor` `@Sendable` () -> Void
     ) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
completionHandler: @escaping @MainActor () -> Void
func webView(
_ webView: WKWebView,
runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: `@escaping` `@MainActor` `@Sendable` () -> Void
) {
🤖 Prompt for AI Agents
In
`@firefox-ios/Client/Frontend/Browser/BrowserViewController/WebEngineIntegration/BrowserWebUIDelegate.swift`
at line 42, The completionHandler parameter declaration in
BrowserWebUIDelegate's method is missing the `@Sendable` annotation; update the
parameter signature so the closure is declared as `@Sendable` `@MainActor` () ->
Void (matching the other completionHandler parameters at lines with similar
signatures) to maintain consistency across BrowserWebUIDelegate and align with
the existing annotated completion handlers.

) {
legacyResponder?.webView?(
webView,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import Shared
import UIKit

class DownloadToast: Toast, DownloadProgressDelegate {
struct UX {
static let buttonSize: CGFloat = 40
}

lazy var progressView: UIView = .build { view in
view.layer.cornerRadius = Toast.UX.toastCornerRadius
}
Expand Down Expand Up @@ -110,10 +106,11 @@ class DownloadToast: Toast, DownloadProgressDelegate {
)
}

init(downloadProgressManager: DownloadProgressManager,
theme: Theme,

completion: @escaping (Bool) -> Void) {
init(
downloadProgressManager: DownloadProgressManager,
theme: Theme,
completion: @MainActor @escaping (Bool) -> Void
) {
self.downloadProgressManager = downloadProgressManager
super.init(frame: .zero)

Expand Down Expand Up @@ -192,8 +189,8 @@ class DownloadToast: Toast, DownloadProgressDelegate {
contentStackView.topAnchor.constraint(equalTo: toastView.topAnchor,
constant: ButtonToast.UX.spacing),

closeButton.heightAnchor.constraint(equalToConstant: UX.buttonSize),
closeButton.widthAnchor.constraint(equalToConstant: UX.buttonSize),
closeButton.heightAnchor.constraint(equalToConstant: 40),
closeButton.widthAnchor.constraint(equalToConstant: 40),
]
)

Expand Down
Loading