Home > Enterprise >  Custom Sign In with Apple in swiftUI using firebase
Custom Sign In with Apple in swiftUI using firebase

Time:08-04

I am trying to create a custom SignInWithApple button with firebase using swiftUI custom button style. in the documentation they are using a ViewController for handling the request and callback. I am using MVVM architecture and i want to know if you can even create a custom style SignInWithApple button like the following picture Custom Button Style

My ButtonView

struct AuthProviderButton: View {
    
    var type: AuthButtonType
    var action: () -> Void
    
    private var authTextType: String {
        switch type {
        case .google:
            return "Continue With Google"
        case .facebook:
            return "Continue With Facebook"
        case .apple:
            return "Continue With Apple"
        }
    }
    
    var body: some View {
        Button(action: {
            HapticManager.instance.impact(style: .medium)
            action()
        }, label: {
            
            HStack {
                Image(type.rawValue)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 20, height: 20)
                    .padding(.horizontal, 2)
                
                
                Text("\(authTextType)")
                    .font(.title2)
                    .foregroundColor(ColorManager.black)
                
                Spacer()
                
            }
            .padding()
            .background {
                RoundedRectangle(cornerRadius: 12)
                    .fill(ColorManager.White)
                    .overlay {
                        RoundedRectangle(cornerRadius: 16)
                            .stroke(ColorManager.BluerpleMain, lineWidth: 2)
                    }
            }
            
        })
    }
}

and for the default apple signInButton in my ViewModel:

//MARK: Apple provider login
extension AuthViewModel {
    
    func handleAppleLogin(credential: ASAuthorizationAppleIDCredential) {
        guard let token = credential.identityToken else {
            print("DEBUG: Error apple Auth with firebase")
            return
        }
        
        guard let tokenString = String(data: token, encoding: .utf8) else {
            print("DEBUG: ERROR With Token")
            return
        }
        
        let firebaseCredential = OAuthProvider.credential(withProviderID: "apple.com", idToken: tokenString, rawNonce: nonce)
        
        Auth.auth().signIn(with: firebaseCredential, completion: { result, error in
            
            if let error = error {
                self.handleError(error: error.localizedDescription)
                return
            }
            
            guard let user = result?.user else { return }
            //MARK: Check if user number exist in Firestore
            self.checkIfUserExistInDatabase(user: user, provider: .apple)
            self.userSession = user
            self.saveSignInStatus()
            
        })
    }
   
    
}

//HELPER METHOD FOR APPLE LOGIN
func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
let charset: [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
}

func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
String(format: "x", $0)
}.joined()

return hashString
}

CodePudding user response:

In your button action, call the following function:

func signInWithApple() {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    let request = appleIDProvider.createRequest()
    request.requestedScopes = [.fullName, .email]
    request.nonce = randomNonceString()
    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
    authorizationController.delegate = self
    authorizationController.performRequests()
}

You can put the above function in your viewModel & call in when pressing the button.

Conform your ViewModel to ASAuthorisationControllerDelegate, & add this method to it:

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    switch authorization.credential {
    case let appleIDCredential as ASAuthorizationAppleIDCredential:
        handleAppleLogin(credential: appleIDCredential)
    default:
        handle
    }
}
  • Related