diff --git a/Sources/Dependencies/DependencyValues/OpenURL.swift b/Sources/Dependencies/DependencyValues/OpenURL.swift index 67dceef9..cb138564 100644 --- a/Sources/Dependencies/DependencyValues/OpenURL.swift +++ b/Sources/Dependencies/DependencyValues/OpenURL.swift @@ -11,7 +11,7 @@ } @available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) - private enum OpenURLKey: DependencyKey { + internal enum OpenURLKey: DependencyKey { static let liveValue = OpenURLEffect { url in let stream = AsyncStream { continuation in let task = Task { @MainActor in @@ -19,6 +19,30 @@ EnvironmentValues().openURL(url) continuation.yield(true) continuation.finish() + #elseif os(macOS) + /// On macOS Sequoia, invokng `EnvironmentValues().openURL(_:completion:)` + /// i.e. with the completion handler, causes an `EXC_BREAKPOINT (SIGTRAP), KERN_INVALID_ADDRESS` + /// runtime crash with `_dispatch_assert_queue_fail` on a non-main thread. + if #available(macOS 15.0, *) { + let openURL = OpenURLAction { url in + EnvironmentValues().openURL(url) + /// However, using `.systemAction` (which may be needed to indicate whether an app + /// is available to handle a URL scheme), seems to cause the completion handler to never return... + /// Therefore, this implementation is actually equivalent to the watchOS one, which always + /// yields `true`. + return .handled + } + + openURL(url) { canOpen in + continuation.yield(canOpen) + continuation.finish() + } + } else { + EnvironmentValues().openURL(url) { canOpen in + continuation.yield(canOpen) + continuation.finish() + } + } #else EnvironmentValues().openURL(url) { canOpen in continuation.yield(canOpen) diff --git a/Tests/DependenciesTests/OpenURLTests.swift b/Tests/DependenciesTests/OpenURLTests.swift new file mode 100644 index 00000000..75a46008 --- /dev/null +++ b/Tests/DependenciesTests/OpenURLTests.swift @@ -0,0 +1,18 @@ +import XCTest + +@testable import Dependencies + +class OpenURLTests: XCTestCase { + @Dependency(\.openURL) var openURL + + /// Please note that running this test may cause side-effects, such as actually opening the + /// given webpage on the Mac that is running the test. + func testOpenURL_liveValue() async { + await withDependencies { + $0.openURL = OpenURLKey.liveValue + } operation: { + let url = URL(string: "https://www.pointfree.co/")! + await self.openURL(url) + } + } +}