Last active
March 1, 2025 03:03
-
-
Save popaaaandrei/7e2e6323d9b6d739f8ea58c394bbbfa6 to your computer and use it in GitHub Desktop.
Google SignIn proxy class that exposes Observables
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Google.swift | |
| // | |
| // | |
| // Created by Andrei on 24/05/16. | |
| // Copyright © 2016 Andrei Popa. All rights reserved. | |
| // | |
| import UIKit | |
| import RxSwift | |
| import Firebase | |
| // add the following to bridging header | |
| // #import <GoogleSignIn/GoogleSignIn.h> | |
| // ============================================================================ | |
| // MARK: GoogleError | |
| // ============================================================================ | |
| public enum GoogleError: ErrorType, CustomStringConvertible { | |
| case NotAuthenticated | |
| case AuthenticationError(message: String) | |
| public var description: String { | |
| switch self { | |
| case NotAuthenticated: | |
| return "Not authenticated" | |
| case AuthenticationError(let message): | |
| return "Authentication error: \(message)" | |
| } | |
| } | |
| } | |
| // ============================================================================ | |
| // MARK: Firebase auth with Google | |
| // ============================================================================ | |
| extension Firebase { | |
| func setupGoogleAuth() { | |
| // pass firebase clientID to Google | |
| if let clientID = clientID { | |
| Google.instance.clientID = clientID | |
| } | |
| // new user chain | |
| Google.instance | |
| .rx_firebaseCredential | |
| .flatMapLatest { credential in | |
| Firebase.instance.rx_signInWithCredential(credential) | |
| } | |
| .subscribeNext({ user in | |
| print("--------------- user logged in: \(user.displayName), \(user.uid)") | |
| if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate { | |
| appDelegate.loggedIn.onNext() | |
| } | |
| }) | |
| .addDisposableTo(Google.instance.disposeBag) | |
| // error chain | |
| Google.instance | |
| .rx_error | |
| .doOnNext({ _ in print("rx_error doOnNext") }) | |
| .filter({ $0 is GoogleError }) | |
| .subscribeNext { error in | |
| print("--------------- error: \(error)") | |
| Firebase.instance.signOut() | |
| } | |
| .addDisposableTo(Google.instance.disposeBag) | |
| } | |
| } | |
| // ============================================================================ | |
| // MARK: Google | |
| // ============================================================================ | |
| class Google : NSObject, GIDSignInDelegate, GIDSignInUIDelegate { | |
| static let instance = Google() | |
| internal let disposeBag = DisposeBag() | |
| let rx_error = ReplaySubject<ErrorType>.create(bufferSize: 1) | |
| var rx_firebaseCredential : Observable<FIRAuthCredential> { | |
| return rx_user | |
| .doOnNext({ _ in print("--------------- rx_firebaseCredential received") }) | |
| .map({ $0.authentication }) | |
| .map({ authentication in | |
| FIRGoogleAuthProvider.credentialWithIDToken(authentication.idToken, | |
| accessToken: authentication.accessToken) | |
| }) | |
| } | |
| private let rx_user = ReplaySubject<GIDGoogleUser>.create(bufferSize: 1) | |
| // view controller that presents the auth UIViewController | |
| var presentingViewController : UIViewController? | |
| // this prevents others from using the | |
| // default '()' initializer for this class. | |
| private override init() { | |
| super.init() | |
| GIDSignIn.sharedInstance().delegate = self | |
| GIDSignIn.sharedInstance().uiDelegate = self | |
| } | |
| func signOut() { | |
| // let hasAuthInKeychain = GIDSignIn.sharedInstance().hasAuthInKeychain() | |
| // print("current user: \(GIDSignIn.sharedInstance().currentUser)") | |
| // print("current user hasAuthInKeychain: \(hasAuthInKeychain)") | |
| GIDSignIn.sharedInstance().signOut() | |
| } | |
| var clientID : String { | |
| get { | |
| return GIDSignIn.sharedInstance().clientID | |
| } | |
| set { | |
| GIDSignIn.sharedInstance().clientID = newValue | |
| } | |
| } | |
| // MARK: GIDSignInDelegate | |
| // ============================================================================ | |
| func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) { | |
| // print("didSignInForUser: \(user)") | |
| if let error = error { | |
| rx_error.onNext(GoogleError.AuthenticationError(message: error.localizedDescription)) | |
| } | |
| if let user = user { | |
| rx_user.onNext(user) | |
| } else { | |
| rx_error.onNext(GoogleError.AuthenticationError(message: "empty user")) | |
| } | |
| } | |
| func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) { | |
| // print("didDisconnectWithUser: \(user)") | |
| rx_error.onNext(GoogleError.NotAuthenticated) | |
| } | |
| // MARK: GIDSignInUIDelegate | |
| // ============================================================================ | |
| func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!) { | |
| if let presentingViewController = presentingViewController { | |
| presentingViewController.presentViewController(viewController, animated: true, completion: nil) | |
| } | |
| } | |
| func signIn(signIn: GIDSignIn!, dismissViewController viewController: UIViewController!) { | |
| viewController.dismissViewControllerAnimated(true, completion: nil) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
in some LoginViewController you can just add a
GIDSignInButton& the following:Google.instance.presentingViewController = selfThe
Googleclass will catch all the delegates and forward relevant information on the Observables:rx_userrx_errorrx_firebaseCredentialHave fun :]