I have a SwiftUI app where I can sign in via Apple Sign In using Firebase Auth. This works completely fine on iPad and iPhone.
However when when running the app via catalyst on Mac, using Apple Sign In I get a crash with the following log.
_AuthenticationServices_SwiftUI/SignInWithAppleButton.swift:303: Fatal error: Attempting to present ASAuthorizationController from a SwiftUI view not in a hierarchy. This should not be possible, please file feedback. 2022-07-13 19:31:29.368989+0100 appname[93200:13915263] _AuthenticationServices_SwiftUI/SignInWithAppleButton.swift:303: Fatal error: Attempting to present ASAuthorizationController from a SwiftUI view not in a hierarchy. This should not be possible, please file feedback. (lldb)
I am not sure what is wrong, I have checked Apple Documentation and am struggling to find a fix.
Apple Sign In Object:
import SwiftUI
import AuthenticationServices
import CryptoKit
@EnvironmentObject var store: Store
struct SignInWithAppleButtonView: View {
//Hashing function using CryptoKit
private func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
return String(format: "%02x", $0)
}.joined()
return hashString
}
// from https://firebase.google.com/docs/auth/ios/apple
private func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
let charset: Array<Character> =
Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
var result = ""
var remainingLength = length
while remainingLength > 0 {
let randoms: [UInt8] = (0 ..< 16).map { _ in
var random: UInt8 = 0
let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
if errorCode != errSecSuccess {
fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
}
return random
}
randoms.forEach { random in
if remainingLength == 0 {
return
}
if random < charset.count {
result.append(charset[Int(random)])
remainingLength -= 1
}
}
}
return result
}
@State var currentNonce:String?
var body: some View {
SignInWithAppleButton(.signIn) { request in
// You can change them if needed.
let nonce = randomNonceString()
currentNonce = nonce
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(nonce)
} onCompletion: { result in
// Switch result
switch result {
// Auth Success
case .success(let authResults):
default:
break
}
case .failure(let error):
print("failure", error)
}
}
.frame(maxWidth: .infinity)
}
Login
import SwiftUI
import AuthenticationServices
import CryptoKit
struct login: View {
@EnvironmentObject var store: Store
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .bottom) {
VStack(alignment: .center, spacing: 20) {
SignInWithAppleButtonView()
.signInWithAppleButtonStyle(.black)
.environmentObject(store)
}
}
}
}
}
Handler
class Store : ObservableObject {
func signInWithAppleHandler(credential: OAuthCredential) {
Auth.auth().signIn(with: credential) { (authResult, error) in
if (error != nil) {
// Error. If error.code == .MissingOrInvalidNonce, make sure
// you're sending the SHA256-hashed nonce as a hex string with
// your request to Apple.
print(error?.localizedDescription as Any)
return
}
print("Signed in")
if let user = authResult?.user {
// Fetch profile
let db = Firestore.firestore()
db.collection("users").document(user.uid).getDocument { [self] (document, error) in
if let document = document, document.exists {
//User exists now save that to current user
_ = document.data().map(String.init(describing:)) ?? "nil"
do {
self.profile = try document.data(as: Profile.self)
}
catch {
print("There was an error getting decoding Profile")
}
if self.profile != nil {
self.userAuthState = .signedIn
self.isNewUser = self.profile!.newUser
self.loadProfileImageFromFirebase(uid: profile!.uid)
}
} else {
// create profile
firestoreManager.createProfile(uid: user.uid, email: user.email ?? "")
fetchProfile(uid: user.uid)
}
}
}
}
}
}
Apple Documentation:
https://developer.apple.com/documentation/authenticationservices/signinwithapplebutton
Firebase Documentation:
https://firebase.google.com/docs/auth/ios/apple