Skip to content

Commit fe01ca6

Browse files
Add visionOS support
Authored-by: Joseph Quigley <[email protected]>
1 parent 30f46ad commit fe01ca6

File tree

8 files changed

+50
-8
lines changed

8 files changed

+50
-8
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Contributors
33

44
Contributors to the codebase, in reverse chronological order:
55

6+
- Joseph Quigley, @josephquigley
67
- Martin Pittenauer, @m4p
78
- Lars, @longinius
89
- Christian Gossain, @cgossain

Sources/Base/OAuth2AuthConfig.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,19 @@ public struct OAuth2AuthConfig {
4040
/// If true it makes the login cancellable, otherwise the cancel button is not shown in the embedded web view.
4141
public var showCancelButton = true
4242

43+
#if os(visionOS) // Must come first per Apple documentation
44+
/// Starting with iOS 9, `SFSafariViewController` will be used for embedded authorization instead of our custom class. You can turn this off here.
45+
public var useSafariView = false
46+
47+
/// Starting with iOS 12, `ASWebAuthenticationSession` can be used for embedded authorization instead of our custom class. You can turn this on here.
48+
public var useAuthenticationSession = true
49+
#else
4350
/// Starting with iOS 9, `SFSafariViewController` will be used for embedded authorization instead of our custom class. You can turn this off here.
4451
public var useSafariView = true
4552

4653
/// Starting with iOS 12, `ASWebAuthenticationSession` can be used for embedded authorization instead of our custom class. You can turn this on here.
4754
public var useAuthenticationSession = false
55+
#endif
4856

4957
/// May be passed through to [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3237231-prefersephemeralwebbrowsersessio).
5058
public var prefersEphemeralWebBrowserSession = false

Sources/Base/OAuth2AuthorizerUI.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ public protocol OAuth2AuthorizerUI {
2929
/// The OAuth2 instance this authorizer belongs to.
3030
var oauth2: OAuth2Base { get }
3131

32+
#if os(visionOS) // Intentionally blank per Apple documentation
33+
#elseif os(iOS)
3234
/**
3335
Open the authorize URL in the OS browser.
3436

3537
- parameter url: The authorize URL to open
3638
- throws: UnableToOpenAuthorizeURL on failure
3739
*/
3840
func openAuthorizeURLInBrowser(_ url: URL) throws
41+
#endif
3942

4043
/**
4144
Tries to use the given context to present the authorization screen. Context could be a UIViewController for iOS or an NSWindow on macOS.

Sources/Flows/OAuth2.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import Foundation
2323
import Base
2424
#if os(macOS)
2525
import macOS
26-
#elseif os(iOS)
26+
#elseif os(iOS) || os(visionOS)
2727
import iOS
2828
#elseif os(tvOS)
2929
import tvOS
@@ -220,14 +220,20 @@ open class OAuth2: OAuth2Base {
220220
- parameter params: Optional key/value pairs to pass during authorization
221221
*/
222222
open func doAuthorize(params: OAuth2StringDict? = nil) throws {
223+
#if os(visionOS) // Must come first per Apple documentation
224+
try doAuthorizeEmbedded(with: authConfig, params: params)
225+
#elseif os(iOS)
223226
if authConfig.authorizeEmbedded {
224227
try doAuthorizeEmbedded(with: authConfig, params: params)
225228
}
226229
else {
227230
try doOpenAuthorizeURLInBrowser(params: params)
228231
}
232+
#endif
229233
}
230234

235+
#if os(visionOS) // Intentionally blank per Apple documentation
236+
#elseif os(iOS)
231237
/**
232238
Open the authorize URL in the OS's browser. Forwards to the receiver's `authorizer`, which is a platform-dependent implementation of
233239
`OAuth2AuthorizerUI`.
@@ -240,6 +246,7 @@ open class OAuth2: OAuth2Base {
240246
logger?.debug("OAuth2", msg: "Opening authorize URL in system browser: \(url)")
241247
try authorizer.openAuthorizeURLInBrowser(url)
242248
}
249+
#endif
243250

244251
/**
245252
Tries to use the current auth config context, which on iOS should be a UIViewController and on OS X a NSViewController, to present the

Sources/Flows/OAuth2PasswordGrant.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import Foundation
2323
import Base
2424
#if os(macOS)
2525
import macOS
26-
#elseif os(iOS)
26+
#elseif os(iOS) || os(visionOS)
2727
import iOS
2828
#elseif os(tvOS)
2929
import tvOS

Sources/iOS/OAuth2Authorizer+iOS.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// See the License for the specific language governing permissions and
1818
// limitations under the License.
1919
//
20-
#if os(iOS)
20+
#if os(visionOS) || os(iOS)
2121

2222
import UIKit
2323
import SafariServices
@@ -37,8 +37,11 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
3737
/// The OAuth2 instance this authorizer belongs to.
3838
public unowned let oauth2: OAuth2Base
3939

40+
#if os(visionOS) // Intentionally blank per Apple documentation
41+
#elseif os(iOS)
4042
/// Used to store the `SFSafariViewControllerDelegate`.
4143
private var safariViewDelegate: AnyObject?
44+
#endif
4245

4346
/// Used to store the authentication session.
4447
private var authenticationSession: AnyObject?
@@ -53,6 +56,8 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
5356

5457
// MARK: - OAuth2AuthorizerUI
5558

59+
#if os(visionOS) // Intentionally blank per Apple documentation
60+
#elseif os(iOS)
5661
/**
5762
Uses `UIApplication` to open the authorize URL in iOS's browser.
5863

@@ -69,6 +74,7 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
6974
throw OAuth2Error.unableToOpenAuthorizeURL
7075
#endif
7176
}
77+
#endif
7278

7379
/**
7480
Tries to use the current auth config context, which on iOS should be a UIViewController, to present the authorization screen.
@@ -78,6 +84,14 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
7884
- parameter at: The authorize URL to open
7985
*/
8086
public func authorizeEmbedded(with config: OAuth2AuthConfig, at url: URL) throws {
87+
#if os(visionOS) // visionOS must be first per Apple documentation
88+
// On visionOS we can only use authentication session, so ignore any configs that say otherwise.
89+
guard let redirect = oauth2.redirect else {
90+
throw OAuth2Error.noRedirectURL
91+
}
92+
93+
authenticationSessionEmbedded(at: url, withRedirect: redirect, prefersEphemeralWebBrowserSession: config.ui.prefersEphemeralWebBrowserSession)
94+
#elseif os(iOS)
8195
if #available(iOS 11, *), config.ui.useAuthenticationSession {
8296
guard let redirect = oauth2.redirect else {
8397
throw OAuth2Error.noRedirectURL
@@ -106,6 +120,7 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
106120
}
107121
}
108122
}
123+
#endif
109124
}
110125

111126
/**
@@ -185,7 +200,8 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
185200

186201

187202
// MARK: - Safari Web View Controller
188-
203+
#if os(visionOS) // Intentionally blank per Apple documentation
204+
#elseif os(iOS)
189205
/**
190206
Presents a Safari view controller from the supplied view controller, loading the authorize URL.
191207

@@ -293,9 +309,12 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
293309

294310
return web
295311
}
312+
#endif
296313
}
297314

298315

316+
#if os(visionOS) // Intentionally blank per Apple documentation
317+
#elseif os(iOS)
299318
/**
300319
A custom `SFSafariViewControllerDelegate` that we use with the safari view controller.
301320
*/
@@ -312,6 +331,7 @@ class OAuth2SFViewControllerDelegate: NSObject, SFSafariViewControllerDelegate {
312331
authorizer.safariViewControllerDidCancel(controller)
313332
}
314333
}
334+
#endif
315335

316336
@available(iOS 13.0, *)
317337
class OAuth2ASWebAuthenticationPresentationContextProvider: NSObject, ASWebAuthenticationPresentationContextProviding {

Sources/iOS/OAuth2CustomAuthorizer+iOS.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
// See the License for the specific language governing permissions and
1818
// limitations under the License.
1919
//
20-
#if os(iOS)
21-
20+
#if os(visionOS) || os(iOS)
2221
import Foundation
2322
import UIKit
2423
#if !NO_MODULE_IMPORT
@@ -30,7 +29,7 @@ import Base
3029
An iOS and tvOS-specific implementation of the `OAuth2CustomAuthorizerUI` protocol which modally presents the login controller.
3130
*/
3231
public class OAuth2CustomAuthorizer: OAuth2CustomAuthorizerUI {
33-
32+
3433
private var presentingController: UIViewController?
3534

3635
public init() { }

Sources/iOS/OAuth2WebViewController+iOS.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
// See the License for the specific language governing permissions and
1818
// limitations under the License.
1919
//
20-
#if os(iOS)
20+
#if os(visionOS) // Intentionally blank per Apple documentation
21+
#elseif os(iOS)
2122

2223
import UIKit
2324
import WebKit
@@ -102,7 +103,10 @@ open class OAuth2WebViewController: UIViewController, WKNavigationDelegate {
102103
override open func loadView() {
103104
edgesForExtendedLayout = .all
104105
extendedLayoutIncludesOpaqueBars = true
106+
#if os(visionOS) // Intentionally blank per Apple documentation
107+
#elseif os(iOS)
105108
automaticallyAdjustsScrollViewInsets = true
109+
#endif
106110

107111
super.loadView()
108112
view.backgroundColor = UIColor.white

0 commit comments

Comments
 (0)