At present, I’m utilizing the next code in my iOS shopper to find out whether or not we have to current a login display screen:
if Auth.auth().currentUser == nil
Right here is the login display screen’s logic:
@objc func handleAppleSignUp() {
Analytics.logEvent("handleAppleSignUp", parameters: nil)
appleSignUpButton?.stopPulseAnimation()
startSignInWithAppleFlow()
}
//
// https://firebase.google.com/docs/auth/ios/apple
//
@obtainable(iOS 13, *)
func startSignInWithAppleFlow() {
let nonce = randomNonceString()
currentNonce = nonce
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(nonce)
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
non-public func randomNonceString(size: Int = 32) -> String {
precondition(size > 0)
var randomBytes = [UInt8](repeating: 0, rely: size)
let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.rely, &randomBytes)
if errorCode != errSecSuccess {
fatalError(
"Unable to generate nonce. SecRandomCopyBytes failed with OSStatus (errorCode)"
)
}
let charset: [Character] =
Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
let nonce = randomBytes.map { byte in
// Decide a random character from the set, wrapping round if wanted.
charset[Int(byte) % charset.count]
}
return String(nonce)
}
@obtainable(iOS 13, *)
non-public func sha256(_ enter: String) -> String {
let inputData = Information(enter.utf8)
let hashedData = SHA256.hash(information: inputData)
let hashString = hashedData.compactMap {
String(format: "%02x", $0)
}.joined()
return hashString
}
}
// https://fluffy.es/sign-in-with-apple-tutorial-ios/
extension LoginViewController: ASAuthorizationControllerPresentationContextProviding {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
// Return the window of the present view controller
return self.view.window!
}
}
extension LoginViewController: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
guard let nonce = currentNonce else {
fatalError("Invalid state: A login callback was acquired, however no login request was despatched.")
}
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identification token")
return
}
guard let idTokenString = String(information: appleIDToken, encoding: .utf8) else {
print("Unable to serialize token string from information: (appleIDToken.debugDescription)")
return
}
// Initialize a Firebase credential, together with the consumer's full title.
let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
rawNonce: nonce,
fullName: appleIDCredential.fullName)
EmulatorUtils.authUseEmulatorIfPossible()
// Check in with Firebase.
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
// Error. If error.code == .MissingOrInvalidNonce, be certain
// you are sending the SHA256-hashed nonce as a hex string with
// your request to Apple.
print(error.localizedDescription)
return
}
// Consumer is signed in to Firebase with Apple.
// ...
Analytics.logEvent("sign_in_success", parameters: nil)
self.delegate?.updateBasedOnLoginStatus()
}
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// Deal with error.
print("Check in with Apple errored: (error)")
}
}
I used to be questioning: can we ever have to deal with login token refreshing manually? A few of my customers have reported that interactions with Firebase Capabilities and Firestore typically fail. In every case, this challenge is resolved by logging out after which logging again in.
If I do have to deal with login token refreshing manually, might somebody clarify how and when to take action?