How to return from the ASWebAutheticationSession completion handler back to the View?
Edit: Just for clearance this is not the original code in my project this is extremely shortened and is just for showcasing what I mean.
Here's an example of a code
struct SignInView: View {
@EnvironmentObject var signedIn: UIState
var body: some View {
let AuthenticationSession = AuthSession()
AuthenticationSession.webAuthSession.presentationContextProvider = AuthenticationSession
AuthenticationSession.webAuthSession.prefersEphemeralWebBrowserSession = true
AuthenticationSession.webAuthSession.start()
}
}
class AuthSession: NSObject, ObservableObject, ASWebAuthenticationPresentationContextProviding {
var webAuthSession = ASWebAuthenticationSession.init(
url: AuthHandler.shared.signInURL()!,
callbackURLScheme: "",
completionHandler: { (callbackURL: URL?, error: Error?) in
// check if any errors appeared
// get code from authentication
// Return to view to move on with code? (return code)
})
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return ASPresentationAnchor()
}
}
So what I'm trying to do is call the sign In process and then get back to the view with the code from the authentication to move on with it.
Could somebody tell me how this may be possible? Thanks.
CodePudding user response:
Not sure if I'm correctly understanding your question but it is normally done with publishers, commonly with the @Published wrapper, an example:
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
Button {
self.viewModel.signIn(user: "example", password: "example")
}
label: {
Text("Sign in")
}
if self.viewModel.signedIn {
Text("Successfully logged in")
}
else if let error = self.viewModel.signingError {
Text("Error while logging in: \(error.localizedDescription)")
}
}
.padding()
}
}
class ViewModel: ObservableObject {
@Published var signingStatus = SigningStatus.idle
var signedIn: Bool {
if case .success = self.signingStatus { return true }
return false
}
var signingError: Error? {
if case .failure(let error) = self.signingStatus { return error }
return nil
}
func signIn(user: String, password: String) {
self.dummyAsyncProcessWithCompletionHandler { [weak self] success in
guard let self = self else { return }
guard success else {
self.updateSigning(.failure(CustomError(errorDescription: "Login failed")))
return
}
self.updateSigning(.success)
}
}
private func updateSigning(_ status: SigningStatus) {
DispatchQueue.main.async {
self.signingStatus = status
}
}
private func dummyAsyncProcessWithCompletionHandler(completion: @escaping (Bool) -> ()) {
Task {
print("Signing in")
try await Task.sleep(nanoseconds: 500_000_000)
guard Int.random(in: 0..<9) % 2 == 0 else {
print("Error")
completion(false)
return
}
print("Success")
completion(true)
}
}
enum SigningStatus {
case idle
case success
case failure(Error)
}
struct CustomError: Error, LocalizedError {
var errorDescription: String?
}
}